Introduction

The following code is specific to the task related fMRI task analysis of the Stress Resilience and the Brain in Medical Students (STRAIN-MD) study. Details of the study can be found in an earlier publication. In short, the study consisted of a within subject design examining real-life stress exposure with Ecological Momentary Assessments(EMA) measures, and an fMRI stress exposure using the Socially Evaluated Cold Pressor task(SECPT). The main aim of the study as whole is to link changes is large scale brain networks under stress to real-life stress and resilience measures. Details of the real-life stress procedure can be found in the previously mentioned publication. During the fMRI session, participants engaged in three tasks. The fMRI tasks are designed to activate specific parts of the brain. Primarily, the Executive Control (ECN), Default Mode (DMN), and Salience (SN) networks. The ECN task is a 2-Back where participants respond every time they see 2-Back number. The DMN task is an associative retrieval task. For this task, participants were shown images that moved to 1 of four corners of the screen outside the scanner. They were then asked to indicate where they saw the images using button presses in the scanner. The third and final task that targeted the SN was an emotional oddball. For this task, participants had to respond to a stream of faces whenever a novel face with an emotional expression was presented. In addition to the actual tasks and their contrasts, we also collect peripheral physiological data. This includes

  • Heart Rate
  • Skin Conductance
  • Salivary Cortisol

These measures were used to validate our laboratory stress induction procedure. In this notebook, we validate the stress induction procedures using the above heart rate and saliva data. We additionally derive a lab-based stress reactivity measure from the salivary cortisol response to stress during the SECPT. We also derive a measure from the real-life stress data that reflects stress reactivity/resilience in daily life. Both the lab stress measure, and the real-life stress measure can then be used in subsequent analysis of fMRI related activity and overall task performance in the corresponding sections below. In order to replicate these analyses, the below libraries are use, in addition to a file with custom functions supplied in the repository.

library(knitr)
knitr::opts_chunk$set(include=TRUE, results='show', message=FALSE, warning=FALSE, comment=NA, echo=T, tidy=TRUE, concordance=TRUE, autodep=TRUE)
options(knitr.table.format = "html", booktabs=TRUE) 
#Cleaning Libs
library(readxl)       # Read excel sheets
library(tidyverse)  
library(plyr)
library(dplyr)
library(broom)         # tidy functions
library (hablar)
library(janitor)
library(data.table)
library(zoo)
# Basic Stats
library (psych)       # Nice descriptives and scaling
library (psycho)      # We use the dPrime Tool
library(Hmisc)        # Girl I dont event know
library(corrr)        # Correlation
library(ppcor)        # Partial Correlation
library(corrplot)     # Correlation matrix plotting
#Linear Modeling
library(lmerTest)     # Main Mixed Models
library(afex)         # Advanced Options Mixed Models
library(optimx)       # Optimizer for MMs
library(jtools)       # Uses summ function for readable models
library(performance)  # Model Diagnostics
library(emmeans)      # used for follow-up tests on lmers
#Plotting
library(ggplot2)      # Standard plotting
library(ggpubr)       # Arrange plots
library(sjPlot)       # Plot regressions and lmer
library(car)          # I use the qqPlot function here
# Fonts and Asthetics
library(stargazer)
library(extrafont)
library(kableExtra)
# Functions and cores
library(future)       # Parallel Processing
library(foreach)      # Parallel for each functins
library(parallel)
library(doSNOW)       # do function over cores
source("functions.R") # Custom Functions
# Make sure lmer contrasts are set to sum 0
options(contrasts=c("contr.sum", "contr.poly"))
# Assign Cores for Parallel processing
ncores <- as.numeric(availableCores())-1
# Load fonts
#font_import()
loadfonts(device="pdf")
# Themes used for ggplots
ggtheme1 <- theme (text=element_text(size=16),
                  legend.position = "none",
                  axis.text.y = element_blank(),axis.text.x = element_text(size=16),
                  axis.ticks.y = element_blank(),
                  plot.title = element_text(size=16, hjust=0.5),
                  panel.background = element_rect(fill="transparent"),
                  panel.grid.minor.y = element_line(size=3),
                  panel.grid.major = element_line(colour = "aliceblue"))
ggtheme2 <- theme(text=element_text(size=11, family="ArialMT"),
                  axis.line = element_line(size = 1, colour = "grey"),
                  panel.background = element_rect(fill="transparent"),
                  plot.background = element_rect(fill = "transparent", color = NA), # bg of the plot
                  panel.grid.minor = element_line(colour="grey95"),
                  panel.grid.major = element_line(colour = "grey95")) 
fmri_colors <- c("#00BFC4", "#7CAE00", "#F8766D", "#00B8E7", "#0CB702", "#E68613" ) # DMN, ECN, SN, Early then Late
stress_colors <-  c("#00BFC4",  "#F8766D", "#7CAE00","#00B8E7", "#E68613")               

1 Real-life Stress

We first start with the stress induction in real life, since to some extent this is a replication of previously done analyses. Here, we used an exam and control week as stressor to see its impact on mood an physiology. This was done prior to any scanning, and you can find out more details in the publication. In short, we found that our stress weeks result in increased subjective stress, and that affect and physiology both change in relation to stress exposure, and subjective stress reports. Our primary goal for the sake of the current project is to derive a measure of stress reactivity in real life that we can use as a fixed effect in our fMRI analyses. We should be able to use this measure to link effects of real life to the lab, to fMRI task performance, or to fMRI task related activity and most importantly large scale network balance.

To this end, we do an interpretation of the residual based regressor, with subjective stress as our exposure measures, and positive affect as our resilience component. This is based on a few different studies (Rafael Kalisch’s work, and some from Sanne Boij). We contemplated using something like emotional inertia and the instability, but these measures are only useful for between subject designs, rather than within.

1.1 Data

We load in the file that we derive in our paper mentioned above. This consists of processed EMA items for subject stress during a week with an exam and another week without an exam (IE. Stress and Control weeks respectively). All data cleaning has already been performed, so we need minimal processing at this stage. The full details of the processing pipeline that was used to generate this data can be found in our previous study, with the associated notebook made available on GitHub. All we need to do is load the data, and do some simple retyping.

# Import Data = Retype
df_EMA <- read.csv2("data/EMA_Clean_Anon.csv", sep = ",")
df_EMA <- df_EMA %>% retype() #%>% print()
df_EMA$week_type <- df_EMA$week_type
df_EMA$Week_Type <- factor(df_EMA$week_type, levels=c(0,1), labels=c("Control", "Stress"))

We also want to dichtomoize our subjective stress levels. We do this by assessing the overall subjective stress, and determining subject-level means. If the stress is higher that the mean, then we get a stress situation. If it is lower, then we get a no stress situation.

df_EMA <- df_EMA %>% dplyr::group_by(castor_record_id) %>% dplyr::mutate(ss_tot=(event_tot+activity_tot+social_tot), ss_tot_c=scale(ss_tot,center=TRUE), 
                                                ss_tot_m=mean(ss_tot_c, na.rm=TRUE), ss_tot_bin=factor(ifelse(ss_tot_c>ss_tot_m, "Stress", "Non-Stress")) ) %>% ungroup() 
df_EMA$mean_stress_z <- scale(df_EMA$mean_stress, center=TRUE, scale=T)

We additionally want to come up with a measure from these EMA weeks that can be related to neuroticism or depressive personality to make sure that whatever measure we derive is actually valid and related to an already established measure of stress sensitivity.

df_psych <- read.csv2("/project/3013068.02/stats/EMA/Questionnaires.csv", sep=",") %>% dplyr::rename(sub_id=castor_record_id)

1.2 Statistics

Primary Models: Daily life differences

We first need to get the main models where we look at the differences in subjective stress (SS) and positive affect (PA) between the control and stress weeks. We use mixed effects models, with random slopes and intercepts for each subject. This allows us to actually get subject level fixed effects for the week type. Its similar to doing individual regressions for each subject to get the Betas for each one. These Betas are used in the next stage. Note that the results of these model are counter intuitive because the subject level fixed effects we for week type is set as Control-Stress. We therefore need to reverse the signs of the fixed effects in order to actually get the results we want (Stress-Control).


Subjective Stress

Model
contrasts(df_EMA$Week_Type) <- contr.treatment(c("Control", "Stress"))
model.stressBIN_week <- glmer(ss_tot_bin ~ Week_Type + (1+Week_Type|castor_record_id), contrasts=list(Week_Type="contr.treatment"),
                              data=df_EMA, family=binomial(), control=glmerControl(calc.derivs=FALSE))
asis_output(tab_model(model.stressBIN_week, show.stat=TRUE, show.se=TRUE)$knitr)
  ss tot bin
Predictors Odds Ratios std. Error CI Statistic p
(Intercept) 0.74 0.04 0.67 – 0.82 -5.64 <0.001
Week_Type [Stress] 1.67 0.14 1.42 – 1.98 6.02 <0.001
Random Effects
σ2 3.29
τ00 castor_record_id 0.11
τ11 castor_record_id.Week_TypeStress 0.38
ρ01 castor_record_id -1.00
N castor_record_id 83
Observations 6153
Marginal R2 / Conditional R2 0.020 / NA


Plot
df_EMA.ss_sum <- df_EMA %>% dplyr::group_by(castor_record_id, week_type, ss_tot_bin) %>% filter(ss_tot_bin=="Stress") %>% dplyr::summarise(ss_tot_bin=length(ss_tot_bin))
`summarise()` has grouped output by 'castor_record_id', 'week_type'. You can override using the `.groups` argument.
plot.stress_week <- ggplot(df_EMA.ss_sum, aes(x=week_type, y=ss_tot_bin, color=castor_record_id)) + 
           geom_line(alpha=0.15, stat="summary") + 
            geom_smooth(aes(color=NA), method="lm", alpha=1, size=1, se=F)+
           scale_x_continuous(breaks=c(0,1),labels = c("Control\nWeek","Stress\nWeek"))+
           ylab("Number of beeps with stress") +
           ggtheme2 +
           theme(legend.position = "none", 
                 axis.title.x=element_blank(), axis.text.x=element_text(size=10, colour="black"),
                 axis.title.y=element_text(size=10), axis.text.y=element_text(size=8, colour="black" ))
plot.stress_week


Positive Affect

Model
model.pos_week <- lmer(mood_positive_cs ~ Week_Type + (1 + Week_Type|castor_record_id),
                       data=df_EMA, 
                       control=lmerControl(calc.derivs =F),
                       contrasts=list(Week_Type=contr.treatment(2)) )
asis_output(tab_model(model.pos_week, show.stat=TRUE, show.se=TRUE)$knitr)
  mood positive cs
Predictors Estimates std. Error CI Statistic p
(Intercept) 6.45 0.10 6.25 – 6.64 63.73 <0.001
Week_Type2 -0.77 0.11 -1.00 – -0.55 -6.80 <0.001
Random Effects
σ2 3.67
τ00 castor_record_id 0.74
τ11 castor_record_id.Week_TypeStress 0.86
ρ01 castor_record_id -0.44
ICC 0.17
N castor_record_id 83
Observations 6155
Marginal R2 / Conditional R2 0.033 / 0.196
Plot
plot.pa_week <- ggplot(df_EMA, aes(x=week_type, y=mood_positive_cs, color=castor_record_id)) + 
            geom_line(alpha=0.15, stat="summary") + 
           geom_smooth(aes(color=NA), method="lm", alpha=1, size=1, se=F)+
           scale_x_continuous(breaks=c(0,1),labels = c("Control\nWeek","Stress\nWeek"))+
           ylab("Average positive affect (a.u.)") +
           ggtheme2 +
           theme(legend.position = "none", 
                 axis.title.x=element_blank(), axis.text.x=element_text(size=10, colour="black"),
                 axis.title.y=element_text(size=10), axis.text.y=element_text(size=8, colour="black" ))
plot.pa_week

Reisdual Resilience Score

We now extract the fixed and random effects of each of our models, so that we can use them in a single linear model. We first do this for SS, and then PA. Finally we combine them into a single data frame that we can use for the analysis. We do this by extracting the fixed effects estimates from the main models of subjective stress and positive affect for the random effect of subject.

# Subjective stress
fixed_stress2 <- coef(model.stressBIN_week)$castor_record_id
fixed_stress2$id <- rownames(fixed_stress2)
random_stress2 <- ranef(model.stressBIN_week)$castor_record_id
# Positive affect
fixed_pos <- (coef(model.pos_week)$castor_record_id)
fixed_pos$id <- rownames(fixed_pos)
random_pos <- ranef(model.pos_week)$castor_record_id

We finally combine them into a single data frame that we will use in the secondary model

df_stressrx <- merge(fixed_stress2, fixed_pos, by="id", suffixes=c("_stress","_pa"))
names(df_stressrx) <- c("id","stress_int","stress_fe",  "pa_fe", "pa_int", "pa_mean")

Model

We now go to our second level models. Here, we model the effect of changes in subjective stress reports on changes in mood between the two weeks. We see a significant relationship between the two. The more stress you experience, the lower your positive affect gets relative to baseline. We extract from the model of change in affect as a function of change in subjective stress reports the fitted values, residuals, predicted value, and plot them. From the residuals, we see that those above the line are people who experience less change in affect in response to stress, and those below experience more reductions in positive affect in response to stress. So those with negative residuals would be stress sensitive, and those without would be resilient.

model.residual_regressorsBIN <- lm(pa_fe ~ stress_fe, data=df_stressrx)
asis_output(tab_model(model.residual_regressorsBIN, show.stat=TRUE, show.se=TRUE)$knitr)
  pa fe
Predictors Estimates std. Error CI Statistic p
(Intercept) 0.43 0.12 0.20 – 0.66 3.70 <0.001
stress_fe -0.84 0.16 -1.16 – -0.51 -5.11 <0.001
Observations 83
R2 / R2 adjusted 0.244 / 0.234
# Binarized Model
df_stressrx$fitsBIN <- model.residual_regressorsBIN$fitted.values
df_stressrx$resBIN <- model.residual_regressorsBIN$res
df_stressrx$effBIN <-model.residual_regressorsBIN$effects
df_stressrx$predBIN <- predict(model.residual_regressorsBIN)

Plot

plot.residual <- ggplot(df_stressrx, aes(x=stress_fe, y=pa_fe)) + 
    geom_smooth(method="lm", se=F, colour="grey")+                          # Plot linear relationship
    geom_point(aes(y=fitsBIN), shape=1, size=0.2)+                          # Fits dots on the line
    geom_segment(aes(xend=stress_fe, yend = fitsBIN), alpha = .2) +      # Fits the lines betweem the fitted values on the line, and residuals
    geom_point(aes(color=resBIN)) +                                         # Draw residual dots + colour them
    scale_color_gradient2(low = "red", mid = "ghostwhite", high = "blue")+  # Scale the colour
    xlab("FE Stress") + ylab("FE Positive Affect") +
    ggtheme2 +
    theme(legend.position = "none", axis.title.x=element_text(size=12), axis.title.y=element_text(size=12),axis.line.x=)
plot.residual

Full Plot

ggarrange(
          ggarrange(NULL,plot.stress_week,  NULL, plot.pa_week, ncol=2, nrow=2, widths=c(0.05,1,1), labels=c("A","", "B")), 
          NULL, 
          plot.residual, widths=c(1,0.05,1.2), 
          ncol=3, labels=c("","C", "")); ggsave("figures/Figure_2_EMA.svg", device="svg", dpi=300, bg="white")
No summary function supplied, defaulting to `mean_se()`
`geom_smooth()` using formula 'y ~ x'
Removed 468 rows containing non-finite values (stat_summary).No summary function supplied, defaulting to `mean_se()`
`geom_smooth()` using formula 'y ~ x'
Removed 468 rows containing non-finite values (stat_smooth).`geom_smooth()` using formula 'y ~ x'

Correlation with Psych

Finally we check the correlation between our subjective stress measure, and our personality traits. This allows us to validate that our stress resilience score is related to previously linked scores from the literature. To do this, we merge the psych data frame containing the questionnaires that participants filled in, with the residual data frame, and do some magic to put all the data together. We then plot a correlation matrix. Our scores are linked to neuroticism, which is great!

df_psych.sub <- df_psych %>% dplyr::rename(id=sub_id) %>% dplyr::select(id, ("neo_o"), contains("neo_c"), contains("neo_e"), contains("neo_a"), contains("neo_n"), contains("bdi_total"), "trait_total")
df_stress.sub <- df_stressrx %>% dplyr::select(id, contains("fe"), starts_with("res") )
df_stress.psych <- merge(df_stress.sub, df_psych.sub, by="id")%>% retype()
names(df_stress.psych) <-c("id", "PA", "SS_BIN", "Res_BIN", "NEO_O", "NEO_C", "NEO_E", "NEO_A", "NEO_N", "BDI", "STAI_T")
df_stress.psych.cor <- df_stress.psych[c(2:11)]
df_stress.psych.cor <- data.frame(lapply(df_stress.psych.cor, function(x) scale(x, center = TRUE, scale=T)))
cormat.str <- rcorr(as.matrix(df_stress.psych.cor))
corrplot(cormat.str$r, method="number", p.mat=cormat.str$P, type="lower", diag=FALSE, insig="pch", cl.pos="n")

asis_output(tab_model(lm(Res_BIN ~ 1 + NEO_N, data=df_stress.psych ))$knitr)
  Res BIN
Predictors Estimates CI p
(Intercept) 0.33 -0.05 – 0.71 0.085
NEO_N -0.21 -0.43 – 0.00 0.054
Observations 81
R2 / R2 adjusted 0.046 / 0.034
ggplot(df_stress.psych, aes(y=NEO_N, x=Res_BIN)) + geom_smooth(method="lm") + ggtheme2

2 Laboratory Stress Induction

Before we do any analysis regarding the effects of stress on the brain and our tasks, we need to validate our stress induction procedure. Since this is a within subject design, all participants underwent both the stress induction procedure, and a matched control procedure. The stress procedure involved a novel experimenter placing the participants foot in ice water of 3 minutes, followed by a difficult mental arithmetic task for another 3 minutes. The control procedure was performed by a familiar experimenter, with room temperature water, and an easy arithmetic task. To validate the procedure, we first analyze our collected physiology data which includes saliva and heart rate measures. We also collect skin conductance data, but that still needs to be done, and is outside the scope of the current paper.

2.1 Data

The saliva measures are derived from samples collected during the scanning at 0 min, 6 min, 30 min, 50 min, and 120 min (approximately) from stress induction/control procedure. Additional samples are collected in the stress/control weeks at home. These samples are analysed offsite and returned in an excel sheet, with the timing logs being recorded in Castor during the scanning. The heart rate measures are also collected during this time via Brainamp with a pulse oxymeter. These measures were cleaned in matlab using HeRa, and then compiled using a custom script. We first do some simple cleaning procedures to make analysis easier for each of the measures.

Saliva

Salivary cortisol and amylase is collected several times in our study. Twice during an exam week, and a control week (non-exam), in addition to the 5 saliva samples during each of the MRI sessions (stress and control). A spreadsheet with the values of the saliva assays was sent from the offsite analysis site. We also record logs for the time at which each sample was acquired. Since this is our main stress validation measure, we need to make sure to get the files clean first. We therefore import the logs containing timing information for our samples to preprocess them and add them to the results from the saliva assays. A few things are done here, including subsetting the data frames, and calculating the relative time of each samples using the first sample as the starting time. We can then import the actual results from the salivary assays. One participant had an incorrect time stamp, so we also correct it here (it had the wrong hour value).

# Get castor df
df_castor <- read_excel("data/castor_data_export.xlsx",sheet = "Study results")

-
/
                                                                                                                                                                                
# Get demographics DF
df_demographics <- read_delim("data/demo_anon.csv", delim="\t") %>% clean_names() %>% dplyr::rename(subject_number="subject_id") %>%
  dplyr::filter(!is.na(contraceptive_use)) %>% 
  dplyr::mutate(sex=ifelse(contraceptive_use=="Male", "Male", "Female"),
                contraceptive_use=ifelse(contraceptive_use=="c", NA, contraceptive_use)) 

indexing demo_anon.csv [====================================================================================================================================] 401.92MB/s, eta:  0s
                                                                                                                                                                                  
                                                   
# Clean Subject numbers
df_castor <- df_castor %>% separate("Record Id", c("subject_number", "dbl_sess"), "_s")
df_castor$dbl_sess[is.na(df_castor$dbl_sess)]  <- 1
df_castor <- subset(df_castor, df_castor$dbl_sess != 2) 
# Subset df
df_castor <- subset(df_castor, select=c("subject_number", "mri_data_control", "mri_data_control_1",
                                                  "cort_1", "cort_2", "cort_3", "cort_4", "cort_5", 
                                                   "cort_1_1", "cort_2_1", "cort_3_1", "cort_4_1", "cort_5_1"))
df_castor[df_castor < 0] <- NA
df_castor <- df_castor[df_castor$mri_data_control!="01-01-2999",] 
df_castor <- unique(df_castor)
# Format dates
df_castor$mri_date_control <- as.Date(df_castor$mri_data_control, format="%d-%m-%Y")
df_castor$mri_date_stress <- as.Date(df_castor$mri_data_control_1, format="%d-%m-%Y")
# Calculate which is first scan
df_castor$first_scan_diff <- NULL
df_castor$first_scan_diff <- df_castor$mri_date_control - df_castor$mri_date_stress
df_castor$first_scan_diff <- as.numeric(df_castor$first_scan_diff, units="days")
# Depednding on difference betweem dates, set first scan
df_castor$first_scan <- "Control"
df_castor$first_scan[df_castor$first_scan_diff > 0] <- "Stress"
# Calcualte time from first sample
df_castor$t_1_c <- as.numeric(difftime(as.ITime(df_castor$cort_1), as.ITime(df_castor$cort_1), units='min'))
df_castor$t_2_c <- as.numeric(difftime(as.ITime(df_castor$cort_2), as.ITime(df_castor$cort_1), units='min'))
df_castor$t_3_c <- as.numeric(difftime(as.ITime(df_castor$cort_3), as.ITime(df_castor$cort_1), units='min')) 
df_castor$t_4_c <- as.numeric(difftime(as.ITime(df_castor$cort_4), as.ITime(df_castor$cort_1), units='min')) 
df_castor$t_5_c <- as.numeric(difftime(as.ITime(df_castor$cort_5), as.ITime(df_castor$cort_1), units='min')) 
# Stress 
df_castor$t_1_s <- as.numeric(difftime(as.ITime(df_castor$cort_1_1), as.ITime(df_castor$cort_1_1 ), units='min')) 
df_castor$t_2_s <- as.numeric(difftime(as.ITime(df_castor$cort_2_1), as.ITime(df_castor$cort_1_1 ), units='min')) 
df_castor$t_3_s <- as.numeric(difftime(as.ITime(df_castor$cort_3_1), as.ITime(df_castor$cort_1_1 ), units='min'))
df_castor$t_4_s <- as.numeric(difftime(as.ITime(df_castor$cort_4_1), as.ITime(df_castor$cort_1_1 ), units='min')) 
df_castor$t_5_s <- as.numeric(difftime(as.ITime(df_castor$cort_5_1), as.ITime(df_castor$cort_1_1 ), units='min')) 
# Make long
df_castor.long <- pivot_longer(df_castor, cols=t_1_c:t_5_s, names_to=c("sample_number"), values_to="time")
# Rename Sample Number
## Control Samples
df_castor.long$sample_number[df_castor.long$sample_number=="t_1_c"] <- "_CMR_1"
df_castor.long$sample_number[df_castor.long$sample_number=="t_2_c"] <- "_CMR_2"
df_castor.long$sample_number[df_castor.long$sample_number=="t_3_c"] <- "_CMR_3"
df_castor.long$sample_number[df_castor.long$sample_number=="t_4_c"] <- "_CMR_4"
df_castor.long$sample_number[df_castor.long$sample_number=="t_5_c"] <- "_CMR_5"
## Stress samples
df_castor.long$sample_number[df_castor.long$sample_number=="t_1_s"] <- "_SMR_1"
df_castor.long$sample_number[df_castor.long$sample_number=="t_2_s"] <- "_SMR_2"
df_castor.long$sample_number[df_castor.long$sample_number=="t_3_s"] <- "_SMR_3"
df_castor.long$sample_number[df_castor.long$sample_number=="t_4_s"] <- "_SMR_4"
df_castor.long$sample_number[df_castor.long$sample_number=="t_5_s"] <- "_SMR_5"
# Get saliva results + clean up
df_saliva <- read_excel ("data/BaLLS_CortisolSamples_Master.xlsx", sheet="mastersheet")

-
/
                                                                                                                                                                                
df_saliva <- df_saliva %>% retype() %>% clean_names()
df_saliva$subject_number <- tolower(df_saliva$subject_number)
df_saliva <- merge(df_saliva, df_demographics, by="subject_number")
# Merge with castor df
df_saliva <- merge(df_saliva, df_castor.long, by=c("subject_number","sample_number"), all=T)
df_saliva <- rename_(df_saliva, "first_scan"="first_scan.y")
#Variable for Scan Type
df_saliva <- df_saliva %>% dplyr::mutate(scan_type=ifelse(str_detect(sample_number, "CMR"), "Control", NA), scan_type=ifelse(str_detect(sample_number, "SMR"), "Stress", scan_type))
# Correct the wrong time
df_saliva$cort_3_1[df_saliva$cort_3_1=="12:25" & df_saliva$subject_number=="sub_023"] <- "13:25"

We next calculate the responses of interest from the cortisol data. These will be single values of responsivity that we can use in follow-up models and include the AUC and Henckens response. For the AUCg and AUCi, we follow the formula derived from Pruessner et al. (2003). We then measure the differences in both the AUCi and the AUCg in the stress and control sessions. For the HPA response from Henckens et al., we instead calculate the difference between the two peak measures in salivary cortisol. The expected peak in our study is sample 3, so we look at the difference in sample 3 in the stress vs control sessions, while correcting for baseline acquired at home. This baseline correction is superior because it is independent of order effects, and scanner apprehension.

# Make a wide df
df_saliva.wide <- df_saliva %>% dplyr::select(subject_number,  first_scan, sample_number, cortisol, alpha_amylase, time) %>% 
  pivot_wider(id_cols=c(subject_number), names_from=sample_number, values_from=c(cortisol, alpha_amylase, time), names_sep="", values_fn=list(cortisol=mean, alpha_amylase=mean, time=mean)) 
# Get the AUCg 
## AUCg Control
df_saliva.wide$AUCg_control <- (
    (((df_saliva.wide$cortisol_CMR_1+df_saliva.wide$cortisol_CMR_2)/2)*(df_saliva.wide$time_CMR_2)) +
(((df_saliva.wide$cortisol_CMR_2+df_saliva.wide$cortisol_CMR_3)/2)*(df_saliva.wide$time_CMR_3-df_saliva.wide$time_CMR_2)) +
(((df_saliva.wide$cortisol_CMR_3+df_saliva.wide$cortisol_CMR_4)/2)*(df_saliva.wide$time_CMR_4-df_saliva.wide$time_CMR_3))
)
## AUCg Stress
df_saliva.wide$AUCg_stress <- (
    (((df_saliva.wide$cortisol_SMR_1+df_saliva.wide$cortisol_SMR_2)/2)*(df_saliva.wide$time_SMR_2)) +
(((df_saliva.wide$cortisol_SMR_2+df_saliva.wide$cortisol_SMR_3)/2)*(df_saliva.wide$time_SMR_3-df_saliva.wide$time_SMR_2)) +
(((df_saliva.wide$cortisol_SMR_3+df_saliva.wide$cortisol_SMR_4)/2)*(df_saliva.wide$time_SMR_4-df_saliva.wide$time_SMR_3)))
# Now get AUCi
## AUCi Control
df_saliva.wide$AUCi_control <- df_saliva.wide$AUCg_control - (df_saliva.wide$cortisol_CMR_1* ((df_saliva.wide$time_CMR_2)+(df_saliva.wide$time_CMR_3-df_saliva.wide$time_CMR_2)+(df_saliva.wide$time_CMR_4-df_saliva.wide$time_CMR_3))) 
## AUCi Stress
df_saliva.wide$AUCi_stress <- df_saliva.wide$AUCg_stress - (df_saliva.wide$cortisol_SMR_1* ((df_saliva.wide$time_SMR_2)+(df_saliva.wide$time_SMR_3-df_saliva.wide$time_SMR_2)+(df_saliva.wide$time_SMR_4-df_saliva.wide$time_SMR_3))) 
## AUC Differences
df_saliva.wide$AUCg_difference <- df_saliva.wide$AUCg_stress - df_saliva.wide$AUCg_control
df_saliva.wide$AUCi_difference <- df_saliva.wide$AUCi_stress - df_saliva.wide$AUCi_control
# Henckens
df_saliva.wide$HPA_act <- (df_saliva.wide$cortisol_SMR_3 - df_saliva.wide$cortisol_CMR_1)/(rowMeans(cbind(df_saliva.wide$cortisol_CW_1, df_saliva.wide$cortisol_CW_2, df_saliva.wide$cortisol_SW_1, df_saliva.wide$cortisol_SW_2), na.rm=TRUE))

In order to plot the results, we also derive the mean times at which the samples we acquired. Finally we can also clean up some factors and other related items in the data frame to make analysis easier. Also filter out the non-scan related saliva samples because these are not really of interest here.

#Time Points for Scan Samples
df_saliva$time_point[df_saliva$sample_number=="_CMR_1"|df_saliva$sample_number=="_SMR_1"]<- mean((df_saliva.wide$time_CMR_1+df_saliva.wide$time_SMR_1)/2, na.rm=TRUE)
df_saliva$time_point[df_saliva$sample_number=="_CMR_2"|df_saliva$sample_number=="_SMR_2"]<-mean((df_saliva.wide$time_CMR_2+df_saliva.wide$time_SMR_2)/2, na.rm=TRUE)
df_saliva$time_point[df_saliva$sample_number=="_CMR_3"|df_saliva$sample_number=="_SMR_3"]<-mean((df_saliva.wide$time_CMR_3+df_saliva.wide$time_SMR_3)/2, na.rm=TRUE)
df_saliva$time_point[df_saliva$sample_number=="_CMR_4"|df_saliva$sample_number=="_SMR_4"]<-mean((df_saliva.wide$time_CMR_4+df_saliva.wide$time_SMR_4)/2, na.rm=TRUE)
df_saliva$time_point[df_saliva$sample_number=="_CMR_5"|df_saliva$sample_number=="_SMR_5"]<-mean((df_saliva.wide$time_CMR_5+df_saliva.wide$time_SMR_5)/2, na.rm=TRUE)
# Make into wide
df_saliva.wide_sub <- df_saliva.wide %>% dplyr::select(subject_number, AUCg_control:HPA_act) 
# Add to the main df
df_saliva <- merge(df_saliva, df_saliva.wide_sub, by="subject_number") 
# Factor variables and filter non needed data
df_saliva$scan_type <- factor(df_saliva$scan_type,levels=c("Control","Stress"), labels=c("Control", "Stress"))
df_saliva.scan <- df_saliva %>% filter(!is.na(first_scan))

Heart Rate

Heart rate measures were collected using a Brainamp based system. We load in the heart rate data, and start by cleaning it up. The actual denoising and artifact removal is done in Matlab using HeRa (mentioned above). For this analysis, we simply import the collected results from this program, and then proceed with a few simple cleaning steps. First we import the data. Then we clean. Certain subjects have issues with the naming of their fMRI EEG recordings of HR data (for example, due to stopping the scan and restarting, or a program crash). So we need to do some cleaning for the names and sessions for each of these subjects individually. This is done below. Its a little rudimentary but this was coded in the first days of using R and its too cumbersome to edit now. Basically, if it ain’t broke, don’t fix it. Finally, we re-order our session indicators, and double check to make sure they all have factors that let us plot and analyse the data effectively.

# Load data
df_HR <- read.csv("data/fmri_HR_clean.csv")
# Drop duplicates
df_HR<-df_HR[!duplicated(df_HR$File_Name),]
#Sub 10:
df_HR$Run[df_HR$SUB_NR == 10 & df_HR$Run == 5] <- 4
df_HR$Run[df_HR$SUB_NR == 10 & df_HR$Run == 0] <- 5
df_HR$Run_time[df_HR$SUB_NR == 10 & df_HR$Run == 4] <- 29
df_HR$Run_time[df_HR$SUB_NR == 10 & df_HR$Run == 5] <- 45
# Sub 52 s1_r1 errors:
df_HR<-df_HR[!(df_HR$SUB_NR==52 & df_HR$Run==1 & df_HR$Session==2),]
df_HR$Run[df_HR$SUB_NR == 52 & df_HR$Run == 2 & df_HR$Session==2] <- 1
df_HR$Run[df_HR$SUB_NR == 52 & df_HR$Run == 3 & df_HR$Session==2] <- 2
df_HR$Run[df_HR$SUB_NR == 52 & df_HR$Run == 4 & df_HR$Session==2] <- 3
df_HR$Run[df_HR$SUB_NR == 52 & df_HR$Run == 5 & df_HR$Session==2] <- 4
df_HR$Run[df_HR$SUB_NR == 52 & df_HR$Run == 0 & df_HR$Session==2] <- 5
# SUB67  Session 2
df_HR$Run[df_HR$File_Name=="sub67_s2_r1-2_fMRI_run_1_TR1500ms_189vols_-10-294s_hera.mat"] <- 2
df_HR$Run[df_HR$File_Name=="sub67_s2_r1-2_fMRI_run_2_TR1500ms_475vols_629-1361s_hera.mat"] <- 3
df_HR$Run[df_HR$File_Name=="sub67_s2_r1-2_fMRI_run_3_TR1500ms_200vols_1380-1700s_hera.mat"] <- 4
df_HR$Run[df_HR$File_Name=="sub67_s2_r1-2_fMRI_run_4_TR1500ms_475vols_1730-2462s_hera.mat"] <- 5
# SUB 71 Session 1
df_HR$Run[df_HR$File_Name=="sub_71_s1_r2_fMRI_run_1_TR1500ms_475vols_161-893s_hera.mat"] <- 6
df_HR$Run[df_HR$File_Name=="sub_71_s1_r2_fMRI_run_2_TR1500ms_200vols_915-1235s_hera.mat"] <- 7
df_HR$Run[df_HR$File_Name=="sub_71_s1_r2_fMRI_run_3_TR1500ms_475vols_1267-1999s_hera.mat"] <- 8
df_HR$Run[df_HR$File_Name=="sub_71_s1_r2_fMRI_run_4_TR1500ms_200vols_2019-2339s_hera.mat"] <- 9
df_HR$Run[df_HR$File_Name=="sub_71_s1_r2_fMRI_run_5_TR1500ms_475vols_2371-3103s_hera.mat"] <- 10
df_HR$Session[df_HR$Session==0 & df_HR$SUB_NR==71] <- 2
# SUB 72 Session 1
df_HR$Run[df_HR$File_Name=="sub_72_s1_r1_fMRI_run_2_TR1500ms_200vols_2900-3220s_hera.mat"]=2
df_HR$Run[df_HR$File_Name=="sub_72_s1_r1_fMRI_run_3_TR1500ms_475vols_3615-4348s_hera.mat"]=3
df_HR$Run[df_HR$File_Name=="sub_72_s1_r1_fMRI_run_4_TR1500ms_200vols_4396-4716s_hera.mat"]=4
df_HR$Run[df_HR$File_Name=="sub_72_s1_r1_fMRI_run_5_TR1500ms_475vols_4764-5497s_hera.mat"]=5
df_HR$Run[df_HR$File_Name=="sub_72_s1_r2_fMRI_run_1_TR1500ms_475vols_176-908s_hera.mat"]=6
df_HR$Run[df_HR$File_Name=="sub_72_s1_r2_fMRI_run_2_TR1500ms_200vols_944-1264s_hera.mat"] =7
df_HR$Run[df_HR$File_Name=="sub_72_s1_r2_fMRI_run_3_TR1500ms_475vols_1289-2021s_hera.mat"]=8
df_HR$Run[df_HR$File_Name=="sub_72_s1_r2_fMRI_run_4_TR1500ms_200vols_2049-2369s_hera.mat"]=9
df_HR$Run[df_HR$File_Name=="sub_72_s1_r2_fMRI_run_5_TR1500ms_475vols_2409-3142s_hera.mat"]=10
df_HR$Session[df_HR$Run>0 & df_HR$SUB_NR==72] <- 1
# SUB 72 Session 2
df_HR$Run[df_HR$File_Name=="sub_72_s2_r1_fMRI_run_1_TR1500ms_475vols_1005-1737s_hera.mat"]=1
df_HR$Run[df_HR$File_Name=="sub_72_s2_r1_fMRI_run_2_TR1500ms_200vols_1768-2088s_hera.mat"]=2
df_HR$Run[df_HR$File_Name=="sub_72_s2_r1_fMRI_run_3_TR1500ms_475vols_2421-3154s_hera.mat"]=3
df_HR$Run[df_HR$File_Name=="sub_72_s2_r1_fMRI_run_4_TR1500ms_200vols_3171-3491s_hera.mat"]=4
df_HR$Run[df_HR$File_Name=="sub_72_s2_r1_fMRI_run_5_TR1500ms_475vols_3505-4238s_hera.mat"]=5
df_HR$Run[df_HR$File_Name=="sub_72_s2_r2_fMRI_run_1_TR1500ms_475vols_374-1106s_hera.mat"]=6
df_HR$Run[df_HR$File_Name=="sub_72_s2_r2_fMRI_run_2_TR1500ms_200vols_1133-1453s_hera.mat"]=7
df_HR$Run[df_HR$File_Name=="sub_72_s2_r2_fMRI_run_3_TR1500ms_475vols_1526-2258s_hera.mat"]=8
df_HR$Run[df_HR$File_Name=="sub_72_s2_r2_fMRI_run_4_TR1500ms_200vols_2337-2657s_hera.mat"]=9
df_HR$Run[df_HR$File_Name=="sub_72_s2_r2_fMRI_run_5_TR1500ms_475vols_2686-3418s_hera.mat"]=10
df_HR$Session[df_HR$Session==0 & df_HR$SUB_NR==72] <- 2
# Now remove anything extra that wasnt cleaned up:
df_HR$Run[df_HR$Run==0] <- NA
# Factor to indicate late and early
df_HR$time_point <- 1 
df_HR$time_point[df_HR$Run > 5] <- 2
df_HR$time_point <- factor(df_HR$time_point, levels=c('1','2'),   labels=c('Early','Late'))
# Factir fir variable for stress and control
df_HR$Session <- factor(df_HR$Session, levels=c('1','2'), labels=c('Control','Stress'))
# Lets also add the first scan coloumn from castor:
df_HR_First <- df_castor
df_HR_First <- separate(df_HR_First, subject_number, c("lead_val", "SUB_NR"), sep="_")
df_HR_First$SUB_NR <- as.integer(df_HR_First$SUB_NR)
df_HR <- merge(df_HR, df_HR_First, by="SUB_NR", all=T)
df_HR$first_scan <- paste(df_HR$first_scan, "First", sep="-")
df_HR <- dplyr::filter(df_HR, !is.na(first_scan))
#Make Separate df for early and late
df_HR_Early <- subset(df_HR, time_point=='Early')
df_HR_Late <- subset(df_HR, time_point=='Late')
df_HR_Early$Run_time[df_HR_Early$Run_time==1] <- 6
# Clean names
df_HR <- df_HR %>% clean_names() %>% filter(first_scan!="NA-First")
df_HR$subject_number <- paste("sub", str_pad(df_HR$sub_nr, 3, pad = "0"), sep="_")
df_HR <- merge(df_HR, df_demographics, by="subject_number") %>% dplyr::rename(first_scan="first_scan.x")

2.2 Statistics

Now that we have cleaned up our physiology data, we can start with the actual statistics of interest. The goal here is to establish increased physiological arousal/stress in the stress session relative to the control. We first take a look at relevant saliva measures (i.e., cortisol and alpha amylase), and then the heart rate measures (using IBI and RMSSD).

Cortisol

We first check the data distribution, which looks like it needs a log transformation. We then run a model, with the addition of time, and controlling for scan order effects. We see in our main model that there is a significant stress*time effect on cortisol. We run a follow-up on the initial model to check the individual time effects. We see that that during the early stress phase, there is a significant increase increase in cortisol levels. We see that there is a significant difference in cortisol between the stress and control sessions, and at specific points in the follow up.

Since we want to use a single metric in the fMRI analysis for the response as a modulator, we check the area under the curve (AUC) between the two time points. We do this with a paired sample t-test since its the difference in a single measure we are testing here. We see there is a significant difference in the AUCi between the sessions. We also test an alternative method for baseline corrections (the Henckens response). To test if there is an increase in cortisol in the stress session, this value should be positive (stress-control/baseline). If stress-control is > 0, then the stress work. So we use a one-sample t-test against 0 to check if it works here.

Hist.

hist(df_saliva.scan$cortisol)

hist(log(df_saliva.scan$cortisol))

Main Effects

model.cort_scan <- glmer(cortisol ~ scan_type*time*first_scan + sex + (1+scan_type|subject_number), 
                         family=Gamma(link="log"),
                         glmerControl(calc.derivs =FALSE),
                         contrasts=list(scan_type="contr.treatment", sex="contr.treatment"),
                         data=df_saliva.scan)
asis_output(tab_model(model.cort_scan, show.stat=TRUE, show.se=TRUE, transform=NULL)$knitr)
  cortisol
Predictors Estimates std. Error CI Statistic p
(Intercept) 1.43 0.06 1.30 – 1.55 22.28 <0.001
scan_type [Stress] -0.03 0.07 -0.17 – 0.11 -0.45 0.654
time -0.00 0.00 -0.00 – -0.00 -4.63 <0.001
first_scan1 0.05 0.06 -0.06 – 0.16 0.82 0.411
sex [Male] -0.16 0.08 -0.32 – -0.01 -2.06 0.040
scan_type [Stress] * time 0.00 0.00 0.00 – 0.00 2.44 0.015
scan_type [Stress] *
first_scan1
-0.03 0.07 -0.17 – 0.10 -0.50 0.618
time * first_scan1 0.00 0.00 -0.00 – 0.00 0.18 0.855
scan_type [Stress] * time
* first_scan1
0.00 0.00 -0.00 – 0.00 0.07 0.941
Random Effects
σ2 0.18
τ00 subject_number 0.09
τ11 subject_number.scan_type1 0.05
ρ01 subject_number 0.06
ICC 0.33
N subject_number 76
Observations 713
Marginal R2 / Conditional R2 0.049 / 0.367
check_model(model.cort_scan)
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.Loading required namespace: qqplotr

Post-Hoc

df_saliva.scan$run <- as.factor(df_saliva.scan$time_point)
model.cort_scan_followup <- glmer(cortisol ~ scan_type*run + scan_type*first_scan + sex + (1+scan_type|subject_number), 
                                  contrasts=list(scan_type="contr.treatment"),
                         family=Gamma(link="log"), 
                         glmerControl(calc.derivs =FALSE),
                         data=df_saliva.scan)
emmeans(model.cort_scan_followup, list(pairwise ~ scan_type*run),by=c("run"), adjust="none")
$`emmeans of scan_type | run`
run = 0:
 scan_type emmean     SE  df asymp.LCL asymp.UCL
 Control     1.33 0.0653 Inf     1.206      1.46
 Stress      1.21 0.0634 Inf     1.087      1.34

run = 14.2042253521127:
 scan_type emmean     SE  df asymp.LCL asymp.UCL
 Control     1.36 0.0652 Inf     1.231      1.49
 Stress      1.19 0.0637 Inf     1.062      1.31

run = 42.7816901408451:
 scan_type emmean     SE  df asymp.LCL asymp.UCL
 Control     1.25 0.0653 Inf     1.119      1.38
 Stress      1.54 0.0637 Inf     1.419      1.67

run = 87.0070422535211:
 scan_type emmean     SE  df asymp.LCL asymp.UCL
 Control     1.09 0.0656 Inf     0.957      1.21
 Stress      1.25 0.0634 Inf     1.126      1.37

run = 159.724637681159:
 scan_type emmean     SE  df asymp.LCL asymp.UCL
 Control     1.09 0.0656 Inf     0.966      1.22
 Stress      1.20 0.0634 Inf     1.071      1.32

Results are averaged over the levels of: first_scan, sex 
Results are given on the log (not the response) scale. 
Confidence level used: 0.95 

$`pairwise differences of scan_type | run`
run = 0:
 2                estimate     SE  df z.ratio p.value
 Control - Stress    0.123 0.0838 Inf   1.464  0.1431

run = 14.2042253521127:
 2                estimate     SE  df z.ratio p.value
 Control - Stress    0.172 0.0840 Inf   2.050  0.0404

run = 42.7816901408451:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   -0.296 0.0840 Inf  -3.529  0.0004

run = 87.0070422535211:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   -0.165 0.0840 Inf  -1.962  0.0498

run = 159.724637681159:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   -0.101 0.0839 Inf  -1.206  0.2280

Results are averaged over the levels of: first_scan, sex 
Results are given on the log (not the response) scale. 

Post-Hoc: Sex/Contraceptive

model.cort_scan_contr <- glmer(cortisol ~ scan_type*time*first_scan + contraceptive_use + (1+scan_type|subject_number), 
                         family=Gamma(link="log"),
                         glmerControl(calc.derivs =FALSE),
                         contrasts=list(scan_type="contr.treatment", contraceptive_use="contr.treatment"),
                         data=df_saliva.scan)
asis_output(tab_model(model.cort_scan_contr, show.stat=TRUE, show.se=TRUE, transform=NULL)$knitr)
  cortisol
Predictors Estimates std. Error CI Statistic p
(Intercept) 1.25 0.07 1.10 – 1.40 16.79 <0.001
scan_type [Stress] -0.01 0.07 -0.16 – 0.13 -0.20 0.844
time -0.00 0.00 -0.00 – -0.00 -4.05 <0.001
first_scan1 0.07 0.06 -0.05 – 0.18 1.14 0.253
contraceptive_use [No] 0.15 0.10 -0.05 – 0.35 1.50 0.134
contraceptive_use [Yes] 0.26 0.10 0.07 – 0.45 2.69 0.007
scan_type [Stress] * time 0.00 0.00 0.00 – 0.00 2.29 0.022
scan_type [Stress] *
first_scan1
-0.04 0.07 -0.19 – 0.10 -0.61 0.543
time * first_scan1 -0.00 0.00 -0.00 – 0.00 -0.33 0.739
scan_type [Stress] * time
* first_scan1
0.00 0.00 -0.00 – 0.00 0.24 0.811
Random Effects
σ2 0.18
τ00 subject_number 0.09
τ11 subject_number.scan_type1 0.05
ρ01 subject_number 0.05
ICC 0.33
N subject_number 69
Observations 662
Marginal R2 / Conditional R2 0.067 / 0.376
check_model(model.cort_scan_contr)
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.

AUCi

df_saliva.wide_sub <- df_saliva.scan %>% dplyr::select(subject_number, age, sex, contraceptive_use, first_scan, AUCg_control:HPA_act) %>% unique() 
describe(df_saliva.wide$AUCi_difference<0)
df_saliva.wide$AUCi_difference < 0 
       n  missing distinct 
      64       23        2 
                      
Value      FALSE  TRUE
Frequency     50    14
Proportion 0.781 0.219
model.auc <- lm(AUCi_stress - AUCi_control ~ 1 + first_scan + sex, data=df_saliva.wide_sub)
summary(model.auc)

Call:
lm(formula = AUCi_stress - AUCi_control ~ 1 + first_scan + sex, 
    data = df_saliva.wide_sub)

Residuals:
    Min      1Q  Median      3Q     Max 
-503.67 -118.63   -4.56  114.89  662.41 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)    95.20      25.03   3.804 0.000332 ***
first_scan1   -39.95      24.88  -1.606 0.113501    
sex1           69.29      25.08   2.763 0.007558 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 198.7 on 61 degrees of freedom
  (15 observations deleted due to missingness)
Multiple R-squared:  0.1506,    Adjusted R-squared:  0.1227 
F-statistic: 5.408 on 2 and 61 DF,  p-value: 0.006886

HPA Response

model.hpa <- lm(HPA_act ~ 1 + first_scan + sex, data=df_saliva.wide_sub)
summary(model.hpa)

Call:
lm(formula = HPA_act ~ 1 + first_scan + sex, data = df_saliva.wide_sub)

Residuals:
    Min      1Q  Median      3Q     Max 
-5.6825 -0.5174 -0.0295  0.4185  3.4922 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept)  0.18614    0.14896   1.250    0.216
first_scan1 -0.01271    0.14699  -0.086    0.931
sex1         0.11093    0.14914   0.744    0.460

Residual standard error: 1.228 on 67 degrees of freedom
  (9 observations deleted due to missingness)
Multiple R-squared:  0.008424,  Adjusted R-squared:  -0.02118 
F-statistic: 0.2846 on 2 and 67 DF,  p-value: 0.7532

Plot

# Make Summary
df_saliva.summ <- summarySEwithin(data=df_saliva.scan, idvar ="subject_number", withinvars =c("scan_type", "time_point"), measurevar = "cortisol", na.rm=TRUE)
Automatically converting the following non-factors to factors: time_point
df_saliva.summ$time_point <- as.character(df_saliva.summ$time_point) %>% as.numeric(df_saliva.summ$time_point)
#Construct the plot
plot.cort_time <- ggplot(df_saliva.summ, aes(y=cortisol, x=time_point,  colour=scan_type)) +
  # Add the scan phases
  geom_rect(aes(xmin=3, xmax=10, ymin=3, ymax=6.2, color=NULL), fill="#E68613", alpha=0.02) +
  geom_rect(aes(xmin=18, xmax=84, ymin=3, ymax=6.2, color=NULL), fill="lightgrey", alpha=0.02) +
  geom_rect(aes(xmin=91, xmax=157, ymin=3, ymax=6.2 ,  color=NULL),fill="lightgrey", alpha=0.02) +
  # Actial plot
  geom_line(size=1, stat = "identity") +
  geom_errorbar(aes(ymin=cortisol-se, ymax=cortisol+se),size=1, width=3, na.rm=T) +
  geom_point(shape=20, size=3) + 
  # Scale to make the graph start at 3
  scale_y_continuous(expand = c(0, 0), limits = c(3, NA)) +
  # Titles and labels
  labs(colour="Session", fill="Phase")+
  xlab("Time (minutes)") + ylab("Cortisol (nmol/L)\n") +
  ggtheme2 + scale_color_manual(values=stress_colors)
#Plot with time 
plot.cort_time; ggsave(filename="figures/Figure_3_LabStres_A.svg", device="svg", plot = plot.cort_time, dpi=300, bg="white") #

Amylase

In addition to the cortisol, we also assayed the levels of alpha amylase, which is used a proxy for adrenaline. We first take a look at the distribution of our variable to see if we need to do any transformations to it before modeling, and then proceed to do the models in the same way we did for the cortisol measures. We see that the distribution is a bit off, and that we need to apply a log transformation to get better fit in our models.

In the main effects of our models, we see that there is a significant effect of time, and that there is a significant interaction between scan order and the stress effects. We investigate this in follow-up models, and see that in people who had a stress session first, the heart rate was higher in the stress than control sessions, but not in those who had the control session first. We go on to plot this effect.

Hist.

#hist(df_saliva.scan$alpha_amylase)
hist(log(df_saliva.scan$alpha_amylase))

Main Effects

model.amylase_scan <- glmer(alpha_amylase ~ scan_type*time*first_scan + sex + (1+scan_type|subject_number), 
                            contrasts=list(scan_type="contr.treatment", sex="contr.treatment"),
                          family=Gamma(link="log"),
                          glmerControl(calc.derivs = FALSE),
                          data=df_saliva.scan)
asis_output(tab_model(model.amylase_scan, show.se=TRUE, show.stat=TRUE, transform=NULL)$knitr)
  alpha amylase
Predictors Estimates std. Error CI Statistic p
(Intercept) 4.03 0.10 3.84 – 4.21 42.37 <0.001
scan_type [Stress] -0.07 0.07 -0.22 – 0.07 -0.97 0.330
time 0.00 0.00 0.00 – 0.00 6.38 <0.001
first_scan1 -0.22 0.08 -0.38 – -0.07 -2.79 0.005
sex [Male] 0.29 0.13 0.03 – 0.55 2.19 0.029
scan_type [Stress] * time 0.00 0.00 -0.00 – 0.00 0.88 0.379
scan_type [Stress] *
first_scan1
0.17 0.07 0.03 – 0.32 2.35 0.019
time * first_scan1 0.00 0.00 -0.00 – 0.00 0.14 0.889
scan_type [Stress] * time
* first_scan1
0.00 0.00 -0.00 – 0.00 0.05 0.958
Random Effects
σ2 0.22
τ00 subject_number 0.29
τ11 subject_number.scan_type1 0.05
ρ01 subject_number 0.05
ICC 0.57
N subject_number 75
Observations 695
Marginal R2 / Conditional R2 0.129 / 0.623
check_model(model.amylase_scan)
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.

Post-Hoc

model.amylase_scan.fu <- glmer(alpha_amylase ~ scan_type*run + scan_type*first_scan + sex +(1+scan_type|subject_number), 
                               contrasts=list(scan_type="contr.treatment"),
                          family=Gamma(link="log"),
                          glmerControl(calc.derivs = FALSE),
                          data=df_saliva.scan)
emmeans(model.amylase_scan.fu, pairwise ~ first_scan*scan_type, adjust="none")
$emmeans
 first_scan scan_type emmean     SE  df asymp.LCL asymp.UCL
 Control    Control     4.12 0.1034 Inf      3.92      4.32
 Stress     Control     4.60 0.1010 Inf      4.40      4.79
 Control    Stress      4.24 0.1013 Inf      4.05      4.44
 Stress     Stress      4.34 0.0996 Inf      4.15      4.54

Results are averaged over the levels of: run, sex 
Results are given on the log (not the response) scale. 
Confidence level used: 0.95 

$contrasts
 contrast                         estimate     SE  df z.ratio p.value
 Control Control - Stress Control  -0.4773 0.1433 Inf  -3.332  0.0009
 Control Control - Control Stress  -0.1255 0.0919 Inf  -1.365  0.1722
 Control Control - Stress Stress   -0.2233 0.1423 Inf  -1.569  0.1167
 Stress Control - Control Stress    0.3519 0.1417 Inf   2.483  0.0130
 Stress Control - Stress Stress     0.2540 0.0878 Inf   2.893  0.0038
 Control Stress - Stress Stress    -0.0978 0.1408 Inf  -0.695  0.4871

Results are averaged over the levels of: run, sex 
Results are given on the log (not the response) scale. 
#emmip(model.amylase_scan.fu, ~ scan_type*first_scan)

Plot

# Make Summary
df_saliva.summ_amy <-  summarySEwithin(data=df_saliva.scan, idvar ="subject_number", withinvars =c("scan_type", "time_point"), betweenvars = "first_scan", measurevar = "alpha_amylase", na.rm=TRUE)
Automatically converting the following non-factors to factors: first_scan, time_point
df_saliva.summ_amy$time_point <- as.character(df_saliva.summ_amy$time_point) %>% as.numeric(df_saliva.summ_amy$time_point)
#Construct the plot
plot.amylase_time <- ggplot(df_saliva.summ_amy , aes(y=alpha_amylase, x=time_point, colour=scan_type)) +
  geom_line(size=1,stat = "identity", na.rm = TRUE, show.legend = TRUE) +
  geom_errorbar(aes(ymin=alpha_amylase-se, ymax=alpha_amylase+se),size=1, width=3, na.rm=T) + 
  geom_point(shape=20, size=3) + 
  geom_rect(mapping=aes(xmin=3, xmax=12, ymin=50, ymax=150, fill='grey'), fill= 'lightgrey',color='lightgrey', alpha=0.05) +
  scale_y_continuous()+# scale_x_continuous(breaks=c(0, 6, 18, 50, 100))+
  ggtitle("Salivary Amylase During Scanning")+labs(colour="Session")+
  xlab("Time (minutes)") + ylab("Amylase (nmol/L)\n")+ 
  ggtheme2 + scale_color_manual(values=stress_colors)
#Plot with error bats and marking significant differences
plot.amylase_time + facet_grid(.~first_scan)

IBI

Now we can look at the changes in the IBI as a function of stress. We expect the IBI to be increased following the stress induction. Here, we analyze the effects of across the 10 scanner runs our participants had (including the resting state runs).In the models, we again include the scan order as a fixed effect in the same way we did for the cortisol analysis.

There is a significant main effect of time, a two-way interaction between stress and scan order, and three-way interaction between stress effects, time, and scan order. A follow-up shows that the stress effect is only present in those who have the stress session first,

Main Effects

# IBI Linear Model
model.IBI_scan <- lmer(ibi ~ session*run*first_scan + sex + (session|sub_nr),
                       contrasts=list(session="contr.treatment", sex="contr.treatment"),
                       data=df_HR)
asis_output(tab_model(model.IBI_scan, show.se=T, show.stat=T)$knitr)
  ibi
Predictors Estimates std. Error CI Statistic p
(Intercept) 67.61 1.22 65.23 – 70.00 55.60 <0.001
session [Stress] 1.30 0.81 -0.29 – 2.89 1.60 0.110
run -0.11 0.04 -0.18 – -0.04 -2.91 0.004
first_scan1 0.97 0.99 -0.96 – 2.90 0.98 0.325
sex [Male] -4.70 1.84 -8.29 – -1.10 -2.56 0.011
session [Stress] * run 0.07 0.05 -0.04 – 0.17 1.24 0.213
session [Stress] *
first_scan1
-2.50 0.81 -4.10 – -0.91 -3.08 0.002
run * first_scan1 -0.12 0.04 -0.20 – -0.05 -3.21 0.001
session [Stress] * run *
first_scan1
0.20 0.05 0.10 – 0.31 3.83 <0.001
Random Effects
σ2 8.10
τ00 sub_nr 59.12
τ11 sub_nr.session1 9.99
ρ01 sub_nr -0.02
ICC 0.88
N sub_nr 75
Observations 1410
Marginal R2 / Conditional R2 0.091 / 0.890
check_model(model.IBI_scan)
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.

Post-Hoc

df_HR$Run <- as.factor(df_HR$run)
model.ibi_scan.fu <- lmer(ibi ~ session*Run*first_scan + sex + (session|sub_nr), 
                           contrasts=list(session="contr.treatment", sex="contr.treatment"),
                         data=df_HR )
emmeans(model.ibi_scan.fu, list(pairwise ~ session*first_scan),by=c("first_scan"), adjust="none")
NOTE: Results may be misleading due to involvement in interactions
$`emmeans of session | first_scan`
first_scan = Control-First:
 session emmean   SE   df lower.CL upper.CL
 Control   64.9 1.38 71.6     62.2     67.7
 Stress    65.2 1.42 72.9     62.4     68.1

first_scan = Stress-First:
 session emmean   SE   df lower.CL upper.CL
 Control   64.4 1.38 72.6     61.6     67.1
 Stress    67.4 1.39 71.3     64.6     70.2

Results are averaged over the levels of: Run, sex 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`pairwise differences of session | first_scan`
first_scan = Control-First:
 2                estimate   SE   df t.ratio p.value
 Control - Stress    -0.28 1.09 70.9  -0.258  0.7975

first_scan = Stress-First:
 2                estimate   SE   df t.ratio p.value
 Control - Stress    -3.04 1.06 70.6  -2.868  0.0054

Results are averaged over the levels of: Run, sex 
Degrees-of-freedom method: kenward-roger 
emmeans(model.ibi_scan.fu, list(pairwise ~ session*Run),by=c("first_scan", "Run"), adjust="none")
$`emmeans of session | first_scan, Run`
first_scan = Control-First, Run = 1:
 session emmean   SE   df lower.CL upper.CL
 Control   67.7 1.44 84.4     64.8     70.5
 Stress    66.0 1.48 85.6     63.1     68.9

first_scan = Control-First, Run = 2:
 session emmean   SE   df lower.CL upper.CL
 Control   64.6 1.43 83.5     61.7     67.4
 Stress    63.9 1.47 85.1     60.9     66.8

first_scan = Control-First, Run = 3:
 session emmean   SE   df lower.CL upper.CL
 Control   65.8 1.43 83.5     62.9     68.6
 Stress    65.9 1.47 85.1     63.0     68.9

first_scan = Control-First, Run = 4:
 session emmean   SE   df lower.CL upper.CL
 Control   64.9 1.43 83.5     62.1     67.8
 Stress    64.9 1.48 85.6     62.0     67.8

first_scan = Control-First, Run = 5:
 session emmean   SE   df lower.CL upper.CL
 Control   66.7 1.43 83.5     63.9     69.6
 Stress    66.7 1.47 85.1     63.7     69.6

first_scan = Control-First, Run = 6:
 session emmean   SE   df lower.CL upper.CL
 Control   63.2 1.44 84.5     60.4     66.1
 Stress    64.3 1.48 86.1     61.3     67.2

first_scan = Control-First, Run = 7:
 session emmean   SE   df lower.CL upper.CL
 Control   62.1 1.44 85.5     59.2     65.0
 Stress    63.8 1.48 86.6     60.8     66.7

first_scan = Control-First, Run = 8:
 session emmean   SE   df lower.CL upper.CL
 Control   64.7 1.43 84.0     61.8     67.5
 Stress    65.2 1.48 86.1     62.2     68.1

first_scan = Control-First, Run = 9:
 session emmean   SE   df lower.CL upper.CL
 Control   64.1 1.44 84.5     61.2     67.0
 Stress    64.4 1.48 85.6     61.5     67.3

first_scan = Control-First, Run = 10:
 session emmean   SE   df lower.CL upper.CL
 Control   65.7 1.44 84.9     62.8     68.5
 Stress    67.3 1.48 85.6     64.3     70.2

first_scan = Stress-First, Run = 1:
 session emmean   SE   df lower.CL upper.CL
 Control   65.8 1.44 85.1     62.9     68.6
 Stress    69.8 1.45 83.5     66.9     72.6

first_scan = Stress-First, Run = 2:
 session emmean   SE   df lower.CL upper.CL
 Control   63.8 1.44 85.1     60.9     66.6
 Stress    66.2 1.45 84.4     63.3     69.1

first_scan = Stress-First, Run = 3:
 session emmean   SE   df lower.CL upper.CL
 Control   64.6 1.44 85.1     61.8     67.5
 Stress    68.2 1.45 84.5     65.3     71.0

first_scan = Stress-First, Run = 4:
 session emmean   SE   df lower.CL upper.CL
 Control   63.5 1.43 84.7     60.6     66.3
 Stress    67.0 1.45 83.6     64.1     69.9

first_scan = Stress-First, Run = 5:
 session emmean   SE   df lower.CL upper.CL
 Control   65.5 1.44 85.6     62.7     68.4
 Stress    69.4 1.45 84.4     66.5     72.3

first_scan = Stress-First, Run = 6:
 session emmean   SE   df lower.CL upper.CL
 Control   63.1 1.44 85.6     60.2     65.9
 Stress    66.4 1.44 82.7     63.5     69.2

first_scan = Stress-First, Run = 7:
 session emmean   SE   df lower.CL upper.CL
 Control   62.3 1.44 85.1     59.5     65.2
 Stress    64.7 1.44 82.7     61.9     67.6

first_scan = Stress-First, Run = 8:
 session emmean   SE   df lower.CL upper.CL
 Control   64.7 1.44 85.6     61.9     67.6
 Stress    67.4 1.44 83.1     64.5     70.3

first_scan = Stress-First, Run = 9:
 session emmean   SE   df lower.CL upper.CL
 Control   64.1 1.44 86.6     61.2     67.0
 Stress    66.1 1.44 83.1     63.2     69.0

first_scan = Stress-First, Run = 10:
 session emmean   SE   df lower.CL upper.CL
 Control   66.4 1.44 86.1     63.5     69.2
 Stress    69.0 1.44 82.7     66.1     71.9

Results are averaged over the levels of: sex 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`pairwise differences of session | first_scan, Run`
first_scan = Control-First, Run = 1:
 3                estimate   SE  df t.ratio p.value
 Control - Stress  1.69983 1.23 116   1.380  0.1702

first_scan = Control-First, Run = 2:
 3                estimate   SE  df t.ratio p.value
 Control - Stress  0.70438 1.22 113   0.575  0.5663

first_scan = Control-First, Run = 3:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -0.14584 1.22 113  -0.119  0.9054

first_scan = Control-First, Run = 4:
 3                estimate   SE  df t.ratio p.value
 Control - Stress  0.00501 1.23 114   0.004  0.9967

first_scan = Control-First, Run = 5:
 3                estimate   SE  df t.ratio p.value
 Control - Stress  0.04284 1.22 113   0.035  0.9722

first_scan = Control-First, Run = 6:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -1.01956 1.23 116  -0.826  0.4104

first_scan = Control-First, Run = 7:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -1.69517 1.24 120  -1.365  0.1749

first_scan = Control-First, Run = 8:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -0.48492 1.23 116  -0.394  0.6946

first_scan = Control-First, Run = 9:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -0.30529 1.23 116  -0.248  0.8047

first_scan = Control-First, Run = 10:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -1.60524 1.23 117  -1.301  0.1960

first_scan = Stress-First, Run = 1:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -3.98740 1.20 116  -3.320  0.0012

first_scan = Stress-First, Run = 2:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -2.43760 1.21 117  -2.021  0.0455

first_scan = Stress-First, Run = 3:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -3.55847 1.21 117  -2.951  0.0038

first_scan = Stress-First, Run = 4:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -3.53374 1.20 115  -2.945  0.0039

first_scan = Stress-First, Run = 5:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -3.84504 1.21 118  -3.183  0.0019

first_scan = Stress-First, Run = 6:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -3.30250 1.20 115  -2.754  0.0068

first_scan = Stress-First, Run = 7:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -2.40852 1.20 114  -2.013  0.0465

first_scan = Stress-First, Run = 8:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -2.69218 1.20 116  -2.241  0.0269

first_scan = Stress-First, Run = 9:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -2.00561 1.21 117  -1.663  0.0990

first_scan = Stress-First, Run = 10:
 3                estimate   SE  df t.ratio p.value
 Control - Stress -2.64410 1.20 116  -2.200  0.0298

Results are averaged over the levels of: sex 
Degrees-of-freedom method: kenward-roger 

Plot

# Make Summary
df_HR.summ <- summarySEwithin(data=df_HR, idvar ="sub_nr", withinvars =c("session", "run"), betweenvars = "first_scan", measurevar = "ibi", na.rm=TRUE)
Automatically converting the following non-factors to factors: first_scan, run
NaNs producedNaNs produced
df_HR.summ <- na.omit(df_HR.summ)
df_HR.summ$run <- as.numeric(as.character(df_HR.summ$run))
df_HR.summ$Phase <- ifelse(df_HR.summ$run<6, "Early", "Late")
#Construct the plot
plot.ibi_time <- ggplot(df_HR.summ, aes(y=ibi, x=run, color=session)) +
  # Make the background session squares
  geom_rect(aes(xmin=0, xmax=0.6, ymin=62, ymax=72, color=NULL), fill="#E68613", alpha=0.02) +
  geom_rect(aes(xmin=0.8, xmax=5.2, ymin=62, ymax=72, color=NULL), fill="lightgrey", alpha=0.02) +
  geom_rect(aes(xmin=5.8, xmax=10.2, ymin=62, ymax=72 ,  color=NULL),fill="lightgrey", alpha=0.02) +
  # Actual Plot
  geom_line(stat = "identity", show.legend = TRUE) +
  geom_errorbar(aes(ymin=ibi-se, ymax=ibi+se), width=0.25, na.rm=T) +
  geom_point(shape=20, size=2, line=2) + 
  # Legen titles and such
  labs(colour="Session", fill="Session")+
  xlab("") + ylab("Heart Rate (BPM)")+  scale_x_continuous(breaks=c(1,2,3,4,5,6,7,8,9,10)) + 
  guides(color=guide_legend(order=2)) +
  ggtheme2 + scale_color_manual(values=stress_colors )  #+ scale_fill_manual(values=c("lightgrey", "lightgrey", ))
Ignoring unknown parameters: line
#plot.ibi_time
plot.ibi_time + facet_grid(first_scan~.)

RMSSD

Now we can take a look at the RMSSD values. First we check the distribution to aid with model decisions and then run the models. There is a significant time by session effect here, with a significant effect of scan order on the session effect. We see that in people who had a stress session first, there is an overall lower RMSSD in the stress session.

Hist.

hist(log(df_HR$rtmssd))

Main Effects

model.rmssd_scan <- glmer(rtmssd ~ session*run*first_scan + sex + (session|sub_nr),
                           contrasts=list(session="contr.treatment", sex="contr.treatment"),
                         data=df_HR,
                         family=Gamma(link="log"),
                         control=glmerControl(calc.derivs=FALSE))
asis_output(tab_model(model.rmssd_scan, show.stat=TRUE, show.se=TRUE, transform=NULL, digits =3 )$knitr)
  rtmssd
Predictors Estimates std. Error CI Statistic p
(Intercept) 3.847 0.046 3.758 – 3.937 84.438 <0.001
session [Stress] 0.019 0.042 -0.064 – 0.102 0.458 0.647
run 0.015 0.003 0.008 – 0.022 4.386 <0.001
first_scan1 -0.020 0.039 -0.097 – 0.056 -0.518 0.604
sex [Male] 0.049 0.060 -0.070 – 0.167 0.803 0.422
session [Stress] * run -0.016 0.005 -0.025 – -0.006 -3.246 0.001
session [Stress] *
first_scan1
0.118 0.042 0.036 – 0.201 2.800 0.005
run * first_scan1 0.006 0.003 -0.001 – 0.013 1.791 0.073
session [Stress] * run *
first_scan1
-0.012 0.005 -0.022 – -0.003 -2.518 0.012
Random Effects
σ2 0.07
τ00 sub_nr 0.06
τ11 sub_nr.session1 0.02
ρ01 sub_nr 0.05
ICC 0.47
N sub_nr 75
Observations 1410
Marginal R2 / Conditional R2 0.039 / 0.492
check_model(model.rmssd_scan)
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.

Post-Hoc

df_HR$Run <- as.factor(df_HR$run)
model.rmssd_scan.fu <- glmer(rtmssd ~ session*Run*first_scan + sex + (session|sub_nr), 
                              contrasts=list(session="contr.treatment"),
                         data=df_HR,
                         family=Gamma(link="log"),
                         control=glmerControl(calc.derivs=FALSE, optimizer ="bobyqa"))
maxfun < 10 * length(par)^2 is not recommended.
emmeans(model.rmssd_scan.fu, list(pairwise ~ session*first_scan),by=c("first_scan"), adjust="none")
NOTE: Results may be misleading due to involvement in interactions
$`emmeans of session | first_scan`
first_scan = Control-First:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.97 0.0482 Inf      3.87      4.06
 Stress    3.95 0.0474 Inf      3.86      4.05

first_scan = Stress-First:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.94 0.0483 Inf      3.85      4.04
 Stress    3.82 0.0463 Inf      3.73      3.91

Results are averaged over the levels of: Run, sex 
Results are given on the log (not the response) scale. 
Confidence level used: 0.95 

$`pairwise differences of session | first_scan`
first_scan = Control-First:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   0.0162 0.0463 Inf   0.350  0.7265

first_scan = Stress-First:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   0.1201 0.0453 Inf   2.650  0.0081

Results are averaged over the levels of: Run, sex 
Results are given on the log (not the response) scale. 
emmeans(model.rmssd_scan.fu, list(pairwise ~ session*Run),by=c("Run"), adjust="none")
NOTE: Results may be misleading due to involvement in interactions
$`emmeans of session | Run`
Run = 1:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.85 0.0448 Inf      3.76      3.94
 Stress    3.88 0.0442 Inf      3.79      3.96

Run = 2:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.91 0.0445 Inf      3.83      4.00
 Stress    3.92 0.0444 Inf      3.83      4.00

Run = 3:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.91 0.0445 Inf      3.82      4.00
 Stress    3.85 0.0444 Inf      3.76      3.93

Run = 4:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.93 0.0444 Inf      3.84      4.02
 Stress    3.89 0.0443 Inf      3.80      3.98

Run = 5:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.90 0.0447 Inf      3.81      3.99
 Stress    3.85 0.0444 Inf      3.76      3.94

Run = 6:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   4.07 0.0450 Inf      3.98      4.15
 Stress    3.91 0.0442 Inf      3.82      4.00

Run = 7:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   4.02 0.0452 Inf      3.93      4.11
 Stress    3.95 0.0443 Inf      3.86      4.04

Run = 8:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.98 0.0449 Inf      3.89      4.07
 Stress    3.92 0.0443 Inf      3.83      4.01

Run = 9:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   4.01 0.0453 Inf      3.92      4.10
 Stress    3.89 0.0441 Inf      3.81      3.98

Run = 10:
 session emmean     SE  df asymp.LCL asymp.UCL
 Control   3.97 0.0453 Inf      3.88      4.06
 Stress    3.82 0.0440 Inf      3.73      3.90

Results are averaged over the levels of: first_scan, sex 
Results are given on the log (not the response) scale. 
Confidence level used: 0.95 

$`pairwise differences of session | Run`
Run = 1:
 2                estimate     SE  df z.ratio p.value
 Control - Stress -0.02615 0.0521 Inf  -0.502  0.6156

Run = 2:
 2                estimate     SE  df z.ratio p.value
 Control - Stress -0.00162 0.0520 Inf  -0.031  0.9751

Run = 3:
 2                estimate     SE  df z.ratio p.value
 Control - Stress  0.06477 0.0520 Inf   1.247  0.2125

Run = 4:
 2                estimate     SE  df z.ratio p.value
 Control - Stress  0.03769 0.0517 Inf   0.729  0.4663

Run = 5:
 2                estimate     SE  df z.ratio p.value
 Control - Stress  0.04939 0.0521 Inf   0.948  0.3429

Run = 6:
 2                estimate     SE  df z.ratio p.value
 Control - Stress  0.15717 0.0521 Inf   3.015  0.0026

Run = 7:
 2                estimate     SE  df z.ratio p.value
 Control - Stress  0.06973 0.0525 Inf   1.329  0.1838

Run = 8:
 2                estimate     SE  df z.ratio p.value
 Control - Stress  0.06161 0.0521 Inf   1.182  0.2372

Run = 9:
 2                estimate     SE  df z.ratio p.value
 Control - Stress  0.11743 0.0524 Inf   2.242  0.0250

Run = 10:
 2                estimate     SE  df z.ratio p.value
 Control - Stress  0.15117 0.0523 Inf   2.892  0.0038

Results are averaged over the levels of: first_scan, sex 
Results are given on the log (not the response) scale. 

Plot

# Make Summary
df_HR.summ <- summarySEwithin(data=df_HR, idvar ="sub_nr", withinvars =c("session", "run"),betweenvars ="first_scan", measurevar = "rtmssd", na.rm=TRUE)
Automatically converting the following non-factors to factors: first_scan, run
NaNs producedNaNs produced
df_HR.summ <- na.omit(df_HR.summ)
df_HR.summ$run <- as.numeric(as.character(df_HR.summ$run))
#Construct the plot
plot.rtmssd_time <- ggplot(df_HR.summ, aes(y=rtmssd, x=run, colour=session)) +
  # Make the background session squares
  geom_rect(aes(xmin=0, xmax=0.6, ymin=47, ymax=72, color=NULL), fill="#E68613", alpha=0.02) +
  geom_rect(aes(xmin=0.8, xmax=5.2, ymin=47, ymax=72, color=NULL), fill="lightgrey", alpha=0.02) +
  geom_rect(aes(xmin=5.8, xmax=10.2, ymin=47, ymax=72 ,  color=NULL),fill="lightgrey", alpha=0.02) +
  # Add labels
  # geom_label(aes(x=0.4, y=75, label="SECPT"), color="black") +
  # geom_label(aes(x=3, y=75, label="Early"), color="black") +
  # geom_label(aes(x=8, y=75, label="Late"), color="black") +
  # Actual Plot
  geom_line(stat = "identity", show.legend = TRUE) +
  geom_errorbar(aes(ymin=rtmssd-se, ymax=rtmssd+se), width=0.25, na.rm=T) +
  geom_point(shape=20, size=2, line=2) + 
  labs(colour="Session", fill="Session")+
  xlab("Scanner Run") + ylab("RMSSD (ms)") +  scale_x_continuous(breaks=c(1,2,3,4,5,6,7,8,9,10)) +scale_y_continuous(n.breaks = 5) +
  ggtheme2 + scale_color_manual(values=stress_colors)
Ignoring unknown parameters: line
plot.rtmssd_time + facet_grid(first_scan~.) 

Full Plot

plot.physio_full <- ggarrange(plot.cort_time, 
                              ggarrange(NULL, (plot.ibi_time + theme(axis.text.x=element_text(size=6)) + facet_grid(first_scan~.)), 
                                       NULL, (plot.rtmssd_time + theme(axis.text.x=element_text(size=6))+ facet_grid(first_scan~.)),
                                       ncol=2, nrow=2, legend="none", align = "hv", labels = c("B", NA, "C", NA), widths=c(0.1,1)), 
          common.legend = T, legend="bottom", widths=c(1.5, 1), labels=c("A"))
# I separated this chunk because ggarrange was producing a random blank plot
plot.physio_full
ggsave("figures/Figure_3_LabStress.svg", dpi=300, device="svg", bg="white", width =8)
Saving 8 x 4.5 in image

3 fMRI: Large-scale networks under stress

We have now validated our stress exposure paradigms in both the lab and real life. We were also able to derive a single measure from each of the stress exposure paradigms we have. That is, we have the AUCi as our indicator of lab stress reactivity, and our residual based stress score for the real-life data. We can incorporate these two measures into our fMRI analysis. We do this in two ways: GLMs in the FSL software tool box, and models here in R for our ROI based analysis.

Before we start this analysis though, we do some signal exploration below. We describe briefly in the Introduction what tasks were used, but not the entirety of the fMRI design. In summary, our participants underwent a stress and control fMRI session. These sessions consisted of two halves, each with 3 runs. The three runs in each half are modeled at the first level in FSL to end up with four fMRI sessions per participant. The first three runs consist of the early phase, while the last three consist of the late phase. This results in:

  • Control Early
  • Control Late
  • Stress Early
  • Stress Late

This design gives us insight into the temporal dynamics of stress reactivity and recovery. We first explore the mean task related activity across all four sessions, and then examine the stress effects (stress-control). These effects are modeled at the subject level in FSL. For both the mean task and the stress related differences, we have two contrasts. The baseline contrast models the mean task activity relative to the implicit baseline, while the task related contrasts models the task related activity during the specific task, relative to the activity during the other tasks. This latter contrast is the main one we are interested in, as it specifically reflects the network resource allocations.

# Load data
df_fmri.signal <-read.csv("/project/3013068.02/stats/fMRI/Signal/fMRI_signal_event_stress_zstat.txt", sep='\t', header=T) %>%
  dplyr::group_by(sub_nr, cope) %>% distinct(Mask,Run, .keep_all=TRUE) %>% ungroup %>% dplyr::mutate(Network=Mask) %>% 
  dplyr::mutate(Contrast=str_replace(cope, "cope1", "2Back"),                                                                     
                Contrast=str_replace(Contrast, "cope2", "NoBack"),
                Contrast=str_replace(Contrast, "cope3", "2Back>NoBack"), 
                Contrast=str_replace(Contrast, "cope4", "Oddball"),
                Contrast=str_replace(Contrast, "cope5", "Noddball"),
                Contrast=str_replace(Contrast, "cope6", "Odd>Nodd"),
                Contrast=str_replace(Contrast, "cope7", "Mem-Rem"),
                Contrast=str_replace(Contrast, "cope8", "Mem-For"),
                Contrast=str_replace(Contrast, "cope9", "Rem>For"),
                Contrast=str_replace(Contrast, "2Back0", "ECN-Con"),
                Contrast=str_replace(Contrast, "2Back1", "SN-Con"),
                Contrast=str_replace(Contrast, "2Back2", "DMN-Con"),
                Contrast=str_replace(Contrast, "2Back3", "2Back+NoBack")) %>%
    dplyr::mutate(Contrast= factor(Contrast, levels=c("2Back", "NoBack", "2Back>NoBack", "ECN-Con", "2Back+NoBack",
                                                      "Oddball", "Noddball", "Odd>Nodd","SN-Con", 
                                                      "Mem-Rem", "Mem-For", "Rem>For", "DMN-Con")))
# Filter for plots and average tests
df_fmri.signal_mean <- df_fmri.signal %>% filter(Run=="Mean")
df_fmri.signal_event <- df_fmri.signal %>% filter(Run!="Mean")

We will also try to link the laboratory stress measure, to the real-life measure. We then try to see how either of these could be related to our large scale network balance. In order to do so, we need to perform some data cleaning, where we add all the data of interest together. We need to combine the fMRI, the cortisol, and the stress-based residual together into one data frame. We also save a data frame with just three columns: subject number, cortisol, and the residualized score to use in FSL directly.

# Merge the dataframes to include the stress reactivity measures
df_combo <- merge(df_stressrx, df_saliva.wide_sub, by.x="id", by.y="subject_number") 
df_combo.fmri <- df_fmri.signal_event
df_combo.fmri$id <- paste("sub", (str_pad(df_combo.fmri$sub_nr, 3, pad = "0")), sep="_") 
df_combo <- merge(df_combo, df_combo.fmri, by="id")
# Rescale and center data points for modeling
## Cortisol
df_combo$HPA_act[is.na(df_combo$HPA_act)] <- mean(df_combo$HPA_act, na.rm=T)
df_combo$AUCi_difference[is.na(df_combo$AUCi_difference)] <- mean(df_combo$AUCi_difference, na.rm=T)
## Rescale
df_combo <- df_combo %>% subset(! is.na(Signal)) %>% dplyr::mutate(HPA_act_z=scale(HPA_act, center=TRUE), stress_rx_z=scale(resBIN, center=TRUE), signal_z=scale(Signal, center=TRUE), AUCi_diff_z=scale(AUCi_difference, center=TRUE))
df_combo <- as.data.frame(df_combo)
# Contrast settings
df_combo$sex <- as.factor(df_combo$sex)
contrasts(df_combo$sex) <- contr.treatment(c("Female", "Male"))
df_combo$contraceptive_use <- as.factor(df_combo$contraceptive_use)
contrasts(df_combo$contraceptive_use) <- contr.treatment(c("Male", "No", "Yes"))
## Save as dataframe for fMRI whole brain analysis
df_combo.tosave <- df_combo %>% dplyr::select(sub_nr, stress_rx_z, HPA_act_z, AUCi_diff_z) %>% unique()
write.csv2(df_combo.tosave, "data/fMRI_regressor.txt", dec="." )
attempt to set 'dec' ignored

3.1 Mean Task Effects

Here we check for the main task effects for our 2Back (ECN), Oddball (SN), and Retrieval (DMN) contrasts. To do this, we plot the mean signal from each the tasks across networks. What we would ideally like to see is the recruitment of the corresponding network-task combinations. While we do see this in the ECN and SN contrasts, we do not really get this effect for the DMN.

ECN: 2Back

# Filter and generate summary
df_fmri.2back <- df_combo %>% subset(cope=="cope1" | cope=="cope2" | cope=="cope3")
df_fmri.2back <- summarySEwithin(data=df_fmri.2back, idvar="sub_nr", measurevar="Signal", withinvars = c("Network", "cope", "Contrast"))
asis_output(tab_model(lmer(Signal ~ 1 + sex+ (1|id), data=(df_combo%>% subset(cope=="cope3" & Network=="ECN"))))$knitr)
  Signal
Predictors Estimates CI p
(Intercept) 0.57 0.41 – 0.74 <0.001
sex [Male] -0.00 -0.27 – 0.26 0.974
Random Effects
σ2 0.46
τ00 id 0.19
ICC 0.29
N id 70
Observations 280
Marginal R2 / Conditional R2 0.000 / 0.292
# Make plot
plot_fmri.mean_ecn <- ggplot(df_fmri.2back , aes(y=Signal, x=Network, color=Network, fill=Network, na.rm = TRUE)) +
  geom_bar(stat="identity", alpha=0.5, position="dodge2" ) +
   geom_errorbar(aes(ymin=Signal-se, ymax=Signal+se, color=Network),size=1, width=0.5, na.rm=T, position=position_dodge(.9)) +
  geom_hline(yintercept=0, color="grey") +
  ggtitle("Parameter Estimates of Task-Network Engagement") + ylab("P.E.") + xlab(" ") + 
  scale_color_manual(values=fmri_colors) + scale_fill_manual(values=fmri_colors) + 
  ggtheme2 + theme(axis.text.y=element_text(size=12), plot.title=element_text(hjust = 0), legend.position="right")
plot_fmri.mean_ecn  + facet_wrap(Contrast~., ncol=3)

SN: Oddball

# Subset + Model
df_fmri.odd <- df_combo %>% subset(cope=="cope4" | cope=="cope5" | cope=="cope6")
df_fmri.odd <- summarySEwithin(data=df_fmri.odd, idvar="sub_nr", measurevar="Signal", withinvars = c("Network", "cope", "Contrast"))
asis_output(tab_model(lmer(Signal ~ 1 + sex + (1|id), data=(df_combo%>% subset(cope=="cope6" & Network=="SN"))))$knitr)
  Signal
Predictors Estimates CI p
(Intercept) 1.09 0.94 – 1.25 <0.001
sex [Male] 0.04 -0.20 – 0.29 0.742
Random Effects
σ2 0.57
τ00 id 0.12
ICC 0.17
N id 70
Observations 280
Marginal R2 / Conditional R2 0.001 / 0.169
# Plot
plot_fmri.mean_sn <- ggplot(df_fmri.odd, aes(y=Signal, x=Network, color=Network, fill=Network, na.rm = TRUE)) +
  geom_bar(stat="identity", alpha=0.5, position="dodge2" ) +
   geom_errorbar(aes(ymin=Signal-se, ymax=Signal+se, color=Network),size=1, width=0.5, na.rm=T, position=position_dodge(.9)) +
  geom_hline(yintercept=0, color="grey") +
  ggtitle("Parameter Estimates of Task-Network Engagement") + ylab("P.E.") + xlab(" ")+ 
  scale_color_manual(values=fmri_colors) + scale_fill_manual(values=fmri_colors) + 
  ggtheme2 + theme(axis.text.y=element_text(size=12), plot.title=element_text(hjust = 0), legend.position="right")
plot_fmri.mean_sn   + facet_wrap(Contrast~.)

DMN: Memory

# Subset + Model
df_fmri.mem <- df_combo %>% subset(cope=="cope7" | cope=="cope8" | cope=="cope9") 
df_fmri.mem <- summarySEwithin(data=df_fmri.mem, idvar="sub_nr", measurevar="Signal", withinvars = c("Network", "cope", "Contrast"))
asis_output(tab_model(lmer(Signal ~ 1 + sex + (1|id), data=(df_combo%>% subset(cope=="cope9" & Network=="DMN"))))$knitr)
  Signal
Predictors Estimates CI p
(Intercept) -0.40 -0.52 – -0.28 <0.001
sex [Male] 0.13 -0.06 – 0.33 0.176
Random Effects
σ2 0.53
τ00 id 0.03
ICC 0.06
N id 70
Observations 280
Marginal R2 / Conditional R2 0.008 / 0.065
# Plot
plot_fmri.mean_dmn <- ggplot(df_fmri.mem, aes(y=Signal, x=Network, color=Network, fill=Network, na.rm = TRUE)) +
  geom_bar(stat="identity", alpha=0.5, position="dodge2" ) +
   geom_errorbar(aes(ymin=Signal-se, ymax=Signal+se, color=Network),size=1, width=0.5, na.rm=T, position=position_dodge(.9)) +
  geom_hline(yintercept=0, color="grey") +
  ggtitle("Parameter Estimates of Task-Network Engagement") + ylab("P.E.") + xlab(" ") + 
  scale_color_manual(values=fmri_colors) + scale_fill_manual(values=fmri_colors) + 
  ggtheme2 + theme(axis.text.y=element_text(size=12), plot.title=element_text(hjust = 0), legend.position="right")
plot_fmri.mean_dmn   + facet_wrap(Contrast~.)

ROI-Task Pairs

df_fmri.mean <- df_combo %>% subset((cope=="cope3" & Network=="ECN") | (cope=="cope6" & Network=="SN") | (cope=="cope9" & Network=="DMN"))
df_fmri.mean_sum <- summarySEwithin(data=df_fmri.mean, idvar="sub_nr", measurevar="Signal", withinvars = c("Network", "cope", "Contrast"))
df_fmri.mean_sum$Contrast <- factor(df_fmri.mean_sum$Contrast)
plot.fmri_mean <- ggplot(df_fmri.mean_sum, aes(y=Signal, x=Network, color=Contrast, fill=Contrast, na.rm = TRUE)) +
  geom_bar(stat="identity", alpha=0.5, position="dodge2", width=0.7 ) +
   geom_errorbar(aes(ymin=Signal-se, ymax=Signal+se),size=1, width=0.4, na.rm=T, position=position_dodge(.9)) +
  geom_hline(yintercept=0, color="grey") +
  ggtitle("Parameter Estimates of Task-Network Engagement") + ylab("Parameter Estiamtes") + xlab("\nROI") + 
  scale_color_manual(values=c("#0CB702", "#F8766D", "#00BFC4")) + scale_fill_manual(values=c("#0CB702", "#F8766D", "#00BFC4" )) + 
  ggtheme2 + 
  theme(plot.title=element_text(hjust = 0), legend.position="right", 
        axis.text.y=element_text(size=12), 
        axis.text.x=element_text(size=12, colour="black"))
plot.fmri_mean

4 fMRI: Tasks

We have three tasks during the fMRI session which we need to analyze for our study as mentioned in the Introduction section. These tasks include a 2-Back, Oddball, and Associative Retrieval. Each requires a slightly different approach so we do some data cleaning in chunks of code before we start.

4.1 Data Cleaning

We first import the data from individual logs. To this end, we have a small function that reads a file and assigns the subject ID. We compile the trial-by-trial logs for all subjects into a single data frame which we then subset for each task separately. We then combine this data frame with the last data frame we used in the previous section for the balance.

# First get a list of all the log files
logs_beh <-(Sys.glob("/project/3013068.02/data/*/logs/mri/*mri*"))
# Make a function to read the log files + add session + subject info
read_add <- function(file, seperator, headers){
    df <- read.csv2(file=file, sep=seperator, header=headers)
    id <- file; id <- sub(".*sub_", "", id); id <- sub("/logs/.*", "", id)
    df$id <- id
    # Select session indicatior
    ses <- file; ses <- sub(".*logs/mri/Sub", "", ses); ses <- sub(".txt.*", "", ses)
    df$ses <- ses
    df }
# Run function
df_task <- rbindlist(lapply(logs_beh, read_add, seperator="\t", headers=FALSE))
# Coloumn headers
names(df_task) <- c("task", "stimulus", "valence", "trial_onset", "trial_offset", "rt", "button_pressed", "button_correct",
                         "block_onset","block_offset","experiment_start", "experiment_end", "sub_id", "session_id")
# Drop the headers added when importing, and retype
df_task <- df_task %>% subset(task != "Trial_Type" & task != "Trial_Type " ) %>% separate(session_id, c("sub", "mri", "session","run"))  %>% retype()
# Make a factor for task types and sessions and runs
df_task$sub_id <- as.factor(df_task$sub_id)
df_task$sub_nr <- paste("sub", (str_pad(df_task$sub_id, 3, pad = "0")), sep="_") 
# Label the tasks
df_task$Task <- factor(df_task$task, level=c(1,2,3), labels=c("oddball", "nback", "memory"))
# Label the session and runs
df_task$Session <- factor(df_task$session, level=c("s1","s2"), labels=c("Control", "Stress"))
df_task$Run <- factor(df_task$run, level=c("r1","r2","r3","r4","r5","r6"), labels=c("r1","r2","r3","r4","r5","r6"))
df_task$run <- as.numeric(df_task$Run)
df_task$Phase <- "Late"
df_task$Phase[df_task$Run =="r1" | df_task$Run =="r2" | df_task$Run =="r3"] <- "Early"
df_task$run <- as.numeric(df_task$Run)
# Subset the fmri dataframe
df_fmri.balance_4tasks <- df_fmri.stress  %>%  pivot_wider(id_cols=c(id, age, sex, contraceptive_use, first_scan, Session, Run), names_from=c(Network), values_from=c(Signal,resBIN,AUCi_difference) ) %>% dplyr::select(1:11,15) 
names(df_fmri.balance_4tasks ) <- c("sub_nr","age","sex", "contraceptive_use", "Scan_Order",  "Session", "Run", "ECN", "SN", "DMN", "resBIN", "AUCi_diff")
# Make the scores
df_fmri.balance_4tasks  <- df_fmri.balance_4tasks  %>% dplyr::mutate(SN_ECN=SN-ECN, ECN_DMN=ECN-DMN, SN_DMN=SN-DMN) %>% dplyr::filter(!is.na(sex))
df_task <- merge(df_task, df_fmri.balance_4tasks, by.x=c("sub_nr", "Session", "Phase"), by.y=c("sub_nr", "Session", "Run"))

Nback

We start of with the nback task. We first correct the nback trials for the baseline reaction speed using the oddball reaction time from each run as the correcting factor. We then also calculate a measure that combines speed and accuracy after that. Here we use the LIASES method, which is a bit complicated. We do this in a separate chunk.

df_task.nback <- df_task %>% group_by(sub_id, Session, Run) %>% dplyr::mutate(odd_mean_rt=mean(ifelse(Task=="oddball", rt, NA), na.rm=TRUE)) %>% ungroup() %>% subset(Task=="nback") %>% subset(rt>200)
df_task.nback$rt_corr <- df_task.nback$rt/df_task.nback$odd_mean_rt
df_task.nback$Hit[df_task.nback$button_pressed>0 & df_task.nback$button_correct>0] <- 1 
df_task.nback$Miss[df_task.nback$button_pressed==0 & df_task.nback$button_correct>0] <- 1 
df_task.nback$FA[df_task.nback$button_pressed>0 & df_task.nback$button_correct==0] <- 1 
df_task.nback$CorrRej[df_task.nback$button_pressed==0 & df_task.nback$button_correct==0] <- 1 

We now calculate the LIASES score based as detailed in the methods paper by André Vandierendonck (2017). We need to get the RT by participant/condition, the SD of both the RTs and the PEs, and then the total PE per condition. SO we can then compare this measure between runs and conditions. The formula is RTj+ (SD(RT)/SD(PE)) * PEj where j=condition. So I first group by subject, get the RT sd, then group by session and run to get the PE per condition, and the RT per condition, and finally I get the overall PE from all conditions.

df_task.nback <- df_task.nback %>% group_by(sub_id) %>% dplyr::mutate(rt_sd=sd(ifelse(rt!=0, rt, NA), na.rm=TRUE)) %>% group_by(sub_id, Session, Run) %>% dplyr::mutate(pe=((sum(FA, na.rm=TRUE)+ sum(Miss, na.rm=TRUE))/length(rt)), rt_mean=mean(ifelse(rt!=0, rt, NA), na.rm=TRUE)) %>% ungroup %>% group_by(sub_id) %>% dplyr::mutate(pe_sd=sd(pe, na.rm=TRUE)) %>% subset(rt>200) %>% ungroup %>% dplyr::mutate(LIASES=rt_mean+(rt_sd/pe_sd)*pe) %>% ungroup()

Memory

For the memory tasks, we have trials with negative, and others with neutral images. So the goal is to look at RT’s, as well as the percent of correct responses. We subset the memory trials from the main data frame here, and then calculate all the measures we need for analysis.

# Filter out the memory trials
df_task.mem <- df_task %>% subset(Task=="memory")
# Label the factors
df_task.mem$valence <- factor(df_task.mem$valence, levels=c(1,2), labels=c("neutral","negative"))
# Get the number of correct answers and valences for sum calculates
df_task.mem$corr_resp[df_task.mem$button_correct==df_task.mem$button_pressed] <- 1
df_task.mem$incorr_resp[df_task.mem$button_correct!=df_task.mem$button_pressed] <- 1
df_task.mem$mem_neu_n[df_task.mem$valence=="neutral"] <- 1
df_task.mem$mem_neg_n[df_task.mem$valence=="negative"] <- 1
# Get averages and the likes
df_task.mem <- df_task.mem %>% group_by(sub_id, Session, Run) %>% dplyr::mutate(
    mem_neu=sum(ifelse(valence=="neutral", mem_neu_n, NA), na.rm=TRUE),
    mem_neg=sum(ifelse(valence=="negative", mem_neg_n, NA), na.rm=TRUE), 
    mem_tot=mem_neg+mem_neu, 
    mem_neu_corr=sum(ifelse(valence=="neutral", corr_resp, NA), na.rm=TRUE),
    mem_neg_corr=sum(ifelse(valence!="neutral", corr_resp, NA), na.rm=TRUE),
    mem_tot_corr=mem_neg_corr+mem_neu_corr, 
    mem_neg_per=mem_neg_corr/mem_neg,
    mem_neu_per=mem_neu_corr/mem_neu, 
    mem_tot_per=(mem_neu_corr+mem_neg_corr)/mem_tot) %>% ungroup

Oddball

We also need to import the data logs for the oddball. The main outcome measure for this task is the oddball recall done outside the scanner, which we analyze a little differently. For this, we need to calculate dprime. I will also be looking at the RTs here for the individual trials during scanning here. So in addition to the previous data frame from the scan, we also import the data frame from outside the scanner. This was already done in python, so we just need to bring in the new data frame with some minor cleaning. We also calculate dprime for the overall performance, and also the performance by valence

# Oddball df
df_task.odd  <- read.csv("/project/3013068.02/stats/fMRI/Behavioral/fmri_recall.csv", sep="\t", header=TRUE)
#Add variable for separating late, early 
df_task.odd$Scan[df_task.odd$session==1 & df_task.odd$run==1] <- 1
df_task.odd$Scan[df_task.odd$session==1 & df_task.odd$run==2] <-2
df_task.odd$Scan[df_task.odd$session==2 & df_task.odd$run==1] <-3
df_task.odd$Scan[df_task.odd$session==2 & df_task.odd$run==2] <-4
#Make phases into factor
df_task.odd$Session <- factor(df_task.odd$session, levels=c(1,2),
                     labels=c('Control', 'Stress'))
df_task.odd$Scan <- factor(df_task.odd$Scan, levels=c(1,2, 3,4),
                     labels=c('Control-Early','Control-Late',
                              'Stress-Early', 'Stress-Late'))
df_task.odd$Run <- factor(df_task.odd$run, levels=c(1,2),
                     labels=c("Early","Late"))
# Add the MRI signal data
df_task.odd <- merge(df_task.odd, df_fmri.balance_4tasks, by.x=c("sub_nr", "Session", "Run"), by.y=c("sub_nr", "Session", "Run"))
# Now we calculate dprime
##First I drop the NAs
df_task.odd <- na.omit(df_task.odd)
df_task.odd_temp <- df_task.odd
# Then make the frame
df_task.odd_dprime_neg <-as.data.frame(dprime(df_task.odd_temp$odd_hits_neg, df_task.odd_temp$odd_FA_neg, n_miss=df_task.odd_temp$odd_miss_neg, n_cr=df_task.odd_temp$odd_correj_neg))
colnames(df_task.odd_dprime_neg) <- paste(colnames(df_task.odd_dprime_neg), "neg", sep = "_")
df_task.odd <- cbind(df_task.odd, df_task.odd_dprime_neg)
df_task.odd_dprime_pos <- as.data.frame(dprime(df_task.odd_temp$odd_hits_pos, df_task.odd_temp$odd_FA_pos, n_miss=df_task.odd_temp$odd_miss_pos, n_cr=df_task.odd_temp$odd_correj_pos))
colnames(df_task.odd_dprime_pos) <- paste(colnames(df_task.odd_dprime_pos), "pos", sep = "_")
df_task.odd <- cbind(df_task.odd, df_task.odd_dprime_pos)
df_task.odd_dprime <- dprime(df_task.odd_temp$odd_hits, df_task.odd_temp$odd_FA, n_miss=df_task.odd_temp$odd_miss, n_cr=df_task.odd_temp$odd_correj)
df_task.odd <- cbind(df_task.odd, df_task.odd_dprime)

4.2 Stats

# Function to run models in parallel
fx.par_model <- function(signal, dv, iv, re, sub_id, fam, data){
  # Right hand formula; # Left hand formula
  rs_formula=dv; 
  ls_formula= paste(iv, signal,  sep="")
  re_formula=paste("(", re, "|", sub_id,")", sep="")
  # Put together ands run the model
  full_form= paste(rs_formula, paste(ls_formula, re_formula, sep="+"),  sep="~")
  if (fam=="lmer"){
      run_model=lmer(as.formula(full_form),
                     contrasts=list(Session="contr.treatment"),
                     data=data, 
                     control=lmerControl(calc.derivs=FALSE, optCtrl=list(maxfun=100000), optimizer="bobyqa"))
  }else{
  run_model=glmer(as.formula(full_form), 
                  contrasts=list(Session="contr.treatment"),
                  data=data,
                  family=fam,
                  control=glmerControl(calc.derivs=FALSE, optCtrl=list(maxfun=100000), optimizer="bobyqa")) }
  return(run_model)}

Nback

For the nback, we will look at three measures: The reaction time (RT), the number of errors (PE), and the combined score using the LIASES method to combine accuracy and speed. We’ll run the RT model on individual trials where there was a response (so only response trials, without factoring in errors). We then look at the error rate using the proportion of misses and false alarms in the overall number of trials, and finally the LIASES that combines these effects, while also account for within subject deviations. These have all been calculated above, so we can just build the models here, and check the results.



Reaction Time

We first filter out the non-responses, and the responses that are too early.I also z-transform, and rescale the responses to make it easier to apply different types of fits. We then look at the distributions as that will help figure out the optimal models to fit. It appears that there is overall no real effect of reaction time, which I find strange looking at the graphs. Its OK though I guess. We don’t run any post-hoc tests due to no main effects in our model either.

Hist.
# First filter out the 0 RTs
df_task.nback_rts <- subset(df_task.nback, rt>200)
df_task.nback_rts$rt_z <- scale(df_task.nback_rts$rt, center=TRUE, scale=TRUE)
df_task.nback_rts$rt_s <- scales::rescale(df_task.nback_rts$rt_z, to=c(0.01,7))
hist((df_task.nback_rts$rt))

Models
# Contrast to investigate
signals=list("", "ECN")
# Run Models in parallel
models.nback_rt <-  mcmapply(signals, FUN=function(X){fx.par_model(signal=X, 
                                               dv="rt_s", 
                                               iv=ifelse(X=="",  "Session*Phase", "1+Session*Phase*"), 
                                               re=ifelse(X=="",  "1+Session*Phase", paste("1+Session*Phase+", X, sep="")), 
                                               sub_id="sub_id", 
                                               fam=Gamma(link="inverse"), 
                                               data=df_task.nback_rts)}, mc.cores=5)
the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used
#HTML Output
tab.2back_rt <- tab_model(models.nback_rt, dv.labels=c("Signal", "Signal ~ ECN"), show.stat=T, show.se=T)
knitr::asis_output(tab.2back_rt$knitr)
  Signal Signal ~ ECN
Predictors Estimates std. Error CI Statistic p Estimates std. Error CI Statistic p
(Intercept) 1.89 0.03 1.83 – 1.95 39.33 <0.001 1.90 0.03 1.83 – 1.96 37.76 <0.001
Session [Stress] 1.00 0.01 0.98 – 1.02 0.26 0.795 1.00 0.01 0.98 – 1.02 -0.07 0.946
Phase1 1.01 0.01 1.00 – 1.02 2.10 0.036 1.01 0.01 0.99 – 1.02 0.99 0.324
Session [Stress] * Phase1 1.00 0.01 0.98 – 1.01 -0.29 0.770 0.99 0.01 0.98 – 1.01 -0.58 0.561
ECN 0.99 0.01 0.97 – 1.00 -1.38 0.166
Session [Stress] * ECN 1.00 0.01 0.98 – 1.02 0.04 0.966
Phase1 * ECN 1.01 0.01 0.99 – 1.02 1.25 0.213
(Session [Stress]
Phase1)
ECN
1.00 0.01 0.98 – 1.02 0.39 0.694
Random Effects
σ2 0.29 0.29
τ00 0.02 sub_id 0.02 sub_id
τ11 0.00 sub_id.Session1 0.00 sub_id.Session1
0.00 sub_id.Phase1 0.00 sub_id.Phase1
0.00 sub_id.Session1:Phase1 0.00 sub_id.ECN
  0.00 sub_id.Session1:Phase1
ρ01 0.07 0.10
-0.04 -0.05
0.04 0.09
  0.05
ICC 0.05  
N 70 sub_id 70 sub_id
Observations 18456 18456
Marginal R2 / Conditional R2 0.000 / 0.053 0.001 / NA



Post-Hoc
joint_tests(models.nback_rt[[2]], by=c("Session", "Phase"))
Session = Control, Phase = Early:
 model term df1 df2 F.ratio p.value
 ECN          1 Inf   0.046  0.8298

Session = Stress, Phase = Early:
 model term df1 df2 F.ratio p.value
 ECN          1 Inf   0.042  0.8380

Session = Control, Phase = Late:
 model term df1 df2 F.ratio p.value
 ECN          1 Inf   3.686  0.0549

Session = Stress, Phase = Late:
 model term df1 df2 F.ratio p.value
 ECN          1 Inf   3.444  0.0635



Plot: Main
df_task.nback_summ <- summarySEwithin(data=df_task.nback_rts, measurevar = "rt", idvar="sub_id", withinvars=c("Session", "Phase"), na.rm=FALSE)
df_task.nback_summ$Phase <- as.numeric(df_task.nback_summ$Phase)
df_task.nback_summ$Session <- relevel(df_task.nback_summ$Session, "Stress")
ggplot(df_task.nback_summ, aes(x=Phase, y=rt, color=Session, fill=Session)) +
    geom_line() + 
    geom_errorbar(aes(ymin=rt-se, ymax=rt+se, color=Session),size=1, width=0.20, na.rm=T)+ 
  ggtheme2



Plot: ECN Phase
ggplot(df_task.nback_rts, aes(y=rt_s, x=ECN, colour=Phase)) + geom_smooth(method="lm") + scale_color_manual(values=stress_colors) + ggtheme2

joint_tests(models.nback_rt[[2]],  by=c("Phase"))
Phase = Early:
 model term  df1 df2 F.ratio p.value
 Session       1 Inf   0.112  0.7380
 ECN           1 Inf   0.000  0.9826
 Session:ECN   1 Inf   0.094  0.7596

Phase = Late:
 model term  df1 df2 F.ratio p.value
 Session       1 Inf   0.061  0.8056
 ECN           1 Inf   6.281  0.0122
 Session:ECN   1 Inf   0.052  0.8204
emtrends(models.nback_rt[[2]], pairwise ~ Phase, var="ECN")
NOTE: Results may be misleading due to involvement in interactions
$emtrends
 Phase ECN.trend      SE  df asymp.LCL asymp.UCL
 Early -0.000172 0.00789 Inf   -0.0156   0.01529
 Late  -0.022360 0.00892 Inf   -0.0398  -0.00487

Results are averaged over the levels of: Session 
Confidence level used: 0.95 

$contrasts
 contrast     estimate     SE  df z.ratio p.value
 Early - Late   0.0222 0.0105 Inf   2.106  0.0352

Results are averaged over the levels of: Session 
ggplot(df_task.nback_rts, aes(y=rt_s, x=SN, colour=Session)) + geom_smooth(method="lm") + scale_color_manual(values=stress_colors) + facet_grid(.~Phase) + ggtheme2



Proportion of Errors

For the error rates, we cant really take the trial-by-trial approach like we do with the reaction times, so instead we will take a look at the error rates per run/condition. We can use this filtered data frame later too for LIASES since we have a similar measure per session*run. We first calculate the number of errors instead of the proportion. Thats mainly because the proportion doesn’t fit will in the models, and isn’t an accurate representation given the zero-inflation. So we use counts instead, that way we can use a Poisson model which would fit the data much better.

# Subset
df_task.nback_sum <- df_task.nback_rts
df_task.nback_sum <- df_task.nback_sum %>% dplyr::select("sub_id", "Session", "Phase", "Run","run", "LIASES","pe", "FA", "Miss", "ECN", "SN", "SN_ECN") %>% group_by(sub_id, Session, Run) %>% dplyr::mutate(FA_count=sum(FA, na.rm=TRUE), Miss_count=sum(Miss, na.rm=TRUE), error_count=(FA_count+Miss_count)) %>% ungroup() %>% dplyr::select("sub_id", "Session", "Phase", "Run","run", "LIASES","pe", "error_count", "ECN", "SN", "SN_ECN") %>% unique()
# Rescale the variables
df_task.nback_sum$LIASES_z <- scale(df_task.nback_sum$LIASES, center=TRUE, scale=TRUE)
df_task.nback_sum$pe_z <- scale(df_task.nback_sum$pe, center=TRUE, scale=TRUE)
Models
# Contrasts to investigate
signals=list("", "ECN")
# Ru moddels in parallel
models.nback_pe <- mcmapply(signals, FUN=function(X){fx.par_model(signal=X, 
                                               dv="error_count", 
                                               iv=ifelse(X=="",  "Session*Phase", "1+Session*Phase*"), 
                                               re=ifelse(X=="",  "1+Session*Phase", paste("1+Session*Phase+", X, sep="")), 
                                               sub_id="sub_id", 
                                               fam=poisson(), 
                                               data=df_task.nback_sum)}, mc.cores=5 )
the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used
#HTML Output
tab.2back_pe <- tab_model(models.nback_pe, dv.labels=signals, show.se=T, show.stat=T)
asis_output(tab.2back_pe$knitr)
  ECN
Predictors Incidence Rate Ratios std. Error CI Statistic p Incidence Rate Ratios std. Error CI Statistic p
(Intercept) 0.99 0.10 0.82 – 1.20 -0.09 0.931 0.95 0.10 0.77 – 1.18 -0.46 0.646
Session [Stress] 0.89 0.07 0.76 – 1.04 -1.51 0.131 0.95 0.09 0.79 – 1.15 -0.53 0.595
Phase1 1.01 0.05 0.92 – 1.10 0.16 0.875 0.99 0.06 0.87 – 1.11 -0.24 0.812
Session [Stress] * Phase1 0.96 0.07 0.84 – 1.11 -0.53 0.594 1.01 0.09 0.85 – 1.19 0.12 0.908
ECN 1.06 0.09 0.91 – 1.25 0.76 0.444
Session [Stress] * ECN 0.91 0.09 0.74 – 1.11 -0.95 0.345
Phase1 * ECN 1.03 0.07 0.90 – 1.18 0.46 0.647
(Session [Stress]
Phase1)
ECN
0.96 0.09 0.80 – 1.16 -0.43 0.668
Random Effects
σ2 0.72 0.72
τ00 0.58 sub_id 0.57 sub_id
τ11 0.03 sub_id.Session1 0.03 sub_id.Session1
0.00 sub_id.Phase1 0.01 sub_id.Phase1
0.01 sub_id.Session1:Phase1 0.03 sub_id.ECN
  0.01 sub_id.Session1:Phase1
ρ01 -0.46 -0.47
-0.08 -0.23
0.20 -0.17
  0.41
ICC   0.44
N 70 sub_id 70 sub_id
Observations 838 838
Marginal R2 / Conditional R2 0.005 / NA 0.004 / 0.447



Post-Hoc: Main
emmeans(models.nback_pe[[1]],  list(pairwise ~Session*Phase), by=c("Phase"), adjust = "tukey")
$`emmeans of Session | Phase`
Phase = Early:
 Session   emmean    SE  df asymp.LCL asymp.UCL
 Control -0.00137 0.110 Inf    -0.217    0.2140
 Stress  -0.15670 0.124 Inf    -0.399    0.0858

Phase = Late:
 Session   emmean    SE  df asymp.LCL asymp.UCL
 Control -0.01545 0.103 Inf    -0.217    0.1859
 Stress  -0.09563 0.127 Inf    -0.344    0.1527

Results are given on the log (not the response) scale. 
Confidence level used: 0.95 

$`pairwise differences of Session | Phase`
Phase = Early:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   0.1553 0.1103 Inf   1.408  0.1590

Phase = Late:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   0.0802 0.0996 Inf   0.805  0.4208

Results are given on the log (not the response) scale. 



Post-Hoc: Brain
joint_tests(models.nback_pe[[2]], by=c("Session", "Phase")) 
Session = Control, Phase = Early:
 model term df1 df2 F.ratio p.value
 ECN          1 Inf   0.795  0.3725

Session = Stress, Phase = Early:
 model term df1 df2 F.ratio p.value
 ECN          1 Inf   0.199  0.6554

Session = Control, Phase = Late:
 model term df1 df2 F.ratio p.value
 ECN          1 Inf   0.082  0.7745

Session = Stress, Phase = Late:
 model term df1 df2 F.ratio p.value
 ECN          1 Inf   0.052  0.8199



Plot
df.nback_error_sum <- summarySEwithin(data=df_task.nback_sum, measurevar="error_count", idvar="sub_id", withinvars=  c("Phase", "Session"), na.rm=FALSE)
df.nback_error_sum$Phase <- as.numeric(df.nback_error_sum$Phase)
df.nback_error_sum$Session <- relevel(df.nback_error_sum$Session, "Stress")
plot.nback_errors <- ggplot(df.nback_error_sum, aes(x=Phase, y=error_count, color=Session, fill=Session)) +
    geom_bar(stat="summary", position="dodge2", alpha=0.5) + 
    geom_errorbar(aes(ymin=error_count-se, ymax=error_count+se, color=Session),size=1, width=0.45, na.rm=T, position=position_dodge(.9) ) + ggtheme2
plot.nback_errors



LIASES

The final measure we use to calculate the n-back performance is LIASES, which combines accuracy and speed. This method is mentioned earlier, and a data frame was subsetted in the chunk looking at the error rates, so we just need to build the model and run it here. I first tested different fits, and it appears that the inverse Gaussian is the best to fit this data.

Hist.
hist((df_task.nback_sum$LIASES_z))



Models
# Parallel
signals=list("",  "ECN" )
models.nback_liases <- mcmapply(signals, FUN=function(X){fx.par_model(signal=X, 
                                               dv="LIASES_z",  
                                               iv=ifelse(X=="",  "Session*Phase", "1+Session*Phase*"), 
                                               re=ifelse(X=="",  "1+Session*Phase", paste("1+Session*Phase+", X, sep="")), 
                                               sub_id="sub_id", 
                                               fam=gaussian(link="inverse"), 
                                               data=df_task.nback_sum)}, mc.cores=5)
#HTML Output
tab.2back_liases <- tab_model(models.nback_liases, dv.labels=c("Signal","Signal ~ ECN" ),show.stat=T, show.se=T)
asis_output(tab.2back_liases$knitr)
  Signal Signal ~ ECN
Predictors Estimates std. Error CI Statistic p Estimates std. Error CI Statistic p
(Intercept) 0.17 0.21 -0.25 – 0.59 0.82 0.415 0.28 0.27 -0.24 – 0.81 1.05 0.292
Session [Stress] -0.29 0.21 -0.71 – 0.13 -1.36 0.174 -0.22 0.26 -0.73 – 0.29 -0.84 0.399
Phase1 0.02 0.13 -0.24 – 0.28 0.12 0.904 -0.09 0.17 -0.42 – 0.24 -0.56 0.579
Session [Stress] * Phase1 -0.20 0.21 -0.61 – 0.21 -0.96 0.338 -0.02 0.24 -0.48 – 0.44 -0.08 0.935
ECN -0.14 0.19 -0.52 – 0.23 -0.75 0.455
Session [Stress] * ECN -0.31 0.26 -0.82 – 0.21 -1.17 0.240
Phase1 * ECN 0.15 0.17 -0.18 – 0.48 0.90 0.368
(Session [Stress]
Phase1)
ECN
-0.16 0.25 -0.64 – 0.33 -0.63 0.528
Random Effects
σ2 0.51 0.51
τ00 2.13 sub_id 2.57 sub_id
τ11 0.57 sub_id.Session1 0.53 sub_id.Session1
0.44 sub_id.Phase1 0.46 sub_id.Phase1
0.53 sub_id.Session1:Phase1 0.12 sub_id.ECN
  0.38 sub_id.Session1:Phase1
ρ01 0.02 0.09
-0.12 -0.12
0.12 -0.74
  0.17
ICC 0.83 0.84
N 70 sub_id 70 sub_id
Observations 838 838
Marginal R2 / Conditional R2 0.012 / 0.836 0.039 / 0.845



Post-Hoc: Behavioural
emmeans(models.nback_liases[[1]], pairwise ~ Session | Phase, adjust="none")
Note: Use 'contrast(regrid(object), ...)' to obtain contrasts of back-transformed estimates
$emmeans
Phase = Early:
 Session  emmean    SE  df asymp.LCL asymp.UCL
 Control  0.1907 0.264 Inf    -0.327     0.709
 Stress  -0.2990 0.232 Inf    -0.754     0.156

Phase = Late:
 Session  emmean    SE  df asymp.LCL asymp.UCL
 Control  0.1586 0.239 Inf    -0.311     0.628
 Stress   0.0675 0.286 Inf    -0.492     0.627

Results are given on the inverse (not the response) scale. 
Confidence level used: 0.95 

$contrasts
Phase = Early:
 contrast         estimate    SE  df z.ratio p.value
 Control - Stress    0.490 0.299 Inf   1.639  0.1012

Phase = Late:
 contrast         estimate    SE  df z.ratio p.value
 Control - Stress    0.091 0.297 Inf   0.306  0.7595

Note: contrasts are still on the inverse scale 



Plot: Behavioral
df_task.nback_summ <- summarySEwithin(df_task.nback, measurevar="LIASES", idvar="sub_id", withinvar=c("Session", "Phase"), na.rm=T)
Automatically converting the following non-factors to factors: Phase
df_task.nback_summ$run <- as.numeric(df_task.nback_summ$Phase)
df_task.nback_summ$Session <- relevel(df_task.nback_summ$Session, "Stress")
ggplot(df_task.nback_summ, aes(x=run, y=LIASES, color=Session, fill=Session)) +
    geom_line() + 
    geom_errorbar(aes(ymin=LIASES-se, ymax=LIASES+se, color=Session),size=0.5, width=0.15, na.rm=T) + 
  ggtheme2 



Post-Hoc: ECN by Session
emtrends(models.nback_liases[[2]], identity ~ Session, var="ECN")
NOTE: Results may be misleading due to involvement in interactions
$emtrends
 Session ECN.trend    SE  df asymp.LCL asymp.UCL
 Control    -0.144 0.192 Inf     -0.52    0.2330
 Stress     -0.451 0.214 Inf     -0.87   -0.0318

Results are averaged over the levels of: Phase 
Confidence level used: 0.95 

$contrasts
 contrast estimate    SE  df z.ratio p.value
 Control    -0.144 0.192 Inf  -0.748  0.4547
 Stress     -0.451 0.214 Inf  -2.109  0.0350

Results are averaged over the levels of: Phase 
#emtrends(models.nback_liases[[3]], pairwise ~ Session | Phase, var="ECN")
ggplot(df_task.nback_sum, aes(x=ECN, y=LIASES_z, colour=Session)) +
  geom_smooth(method="lm", se=T) + 
  xlab("ECN Activity") + ylab("LIASES Accuracy Score") +
  ggtheme2  + scale_color_manual(values=stress_colors)


Memory

For the memory task, we look at the reaction time to the stimuli, split by valence, and the recognition of the images we presented them with outside the scanner. For the RT data, we will take a look at individual trials, and then for the recognition of the images we take a look at the average reposes per run or phase, depending on the model fits best. We first also remove any rts that are less than 200ms as those are just too quick, and we also rescale the RT variables.

df_task.mem <- df_task.mem %>% subset(rt>=200)
df_task.mem$rt_z <- scale(df_task.mem$rt)
df_task.mem$rt_s <- scales::rescale(df_task.mem$rt_z, to=c(1,6))

Recognition

We next look at the ability to recall the object-location associations. We first will look at overall recall, then take a look at the recall by valence associations to see if the negative or positively valent images are remembered better. First I subset the data, and make the data frame a bit longer so that we have percent correct for each of the neutral and the negative items in one column.

# Subset the neutral item correct response rates
df_task.mem_neu <- df_task.mem %>% dplyr::select("sub_id", "Session", "Phase", "Run","run", "mem_neu_per", "DMN") %>% unique() %>% dplyr::rename(per_cor=mem_neu_per) %>% mutate(valence="neu")
# Do the same for the negative items
df_task.mem_neg <- df_task.mem %>% dplyr::select("sub_id", "Session", "Phase", "Run","run", "mem_neg_per", "DMN") %>% unique() %>% dplyr::rename(per_cor=mem_neg_per)  %>% mutate(valence="neg")
# Bind them into one dataframe
df_task.mem_cor <- rbind.data.frame(df_task.mem_neg, df_task.mem_neu)

Now we can also check out the distribution of the correct response rates for each of the valences to help pick the most suitable model family. We see that both valences look similar, but skewed left.

Hist.
hist(df_task.mem_neu$per_cor)

hist(df_task.mem_neg$per_cor)



Chance Level
model.memory_chance <- t.test(df_task.mem$mem_tot_per, mu=0.25)
tidy(model.memory_chance)



Models
# Main
model.mem_correct <- lmer(per_cor ~ Session*Phase*valence + (1+Session*Phase|sub_id),
                          contrasts=list(Session="contr.treatment"),
                           data=df_task.mem_cor,
                           control=lmerControl(calc.derivs = FALSE, optCtrl=list(maxfun=100000)) )
#check_model(model.mem_correct)
# Brain
model.mem_correct_brain <- lmer(per_cor ~ Session*Phase*DMN + valence + (1+Session*Phase*DMN|sub_id),
                                contrasts=list(Session="contr.treatment"),
                           data=df_task.mem_cor,
                           control=lmerControl(calc.derivs = FALSE, optimizer="bobyqa", optCtrl=list(maxfun=100000)) )
# HTM Table
asis_output(tab_model(model.mem_correct, model.mem_correct_brain)$knitr)
  per cor per cor
Predictors Estimates CI p Estimates CI p
(Intercept) 0.61 0.57 – 0.64 <0.001 0.62 0.58 – 0.66 <0.001
Session [Stress] 0.01 -0.01 – 0.03 0.474 0.00 -0.02 – 0.03 0.841
Phase1 -0.01 -0.02 – 0.01 0.581 -0.01 -0.03 – 0.01 0.510
valence1 0.03 0.02 – 0.04 <0.001 0.03 0.02 – 0.03 <0.001
Session [Stress] * Phase1 0.01 -0.01 – 0.03 0.306 0.01 -0.02 – 0.04 0.421
Session [Stress] *
valence1
-0.00 -0.02 – 0.01 0.856
Phase1 * valence1 -0.00 -0.01 – 0.01 0.440
Session [Stress] * Phase1
* valence1
0.00 -0.01 – 0.02 0.853
DMN 0.02 -0.00 – 0.05 0.099
Session [Stress] * DMN -0.01 -0.04 – 0.02 0.575
Phase1 * DMN -0.01 -0.04 – 0.02 0.623
(Session [Stress]
Phase1)
DMN
0.00 -0.03 – 0.04 0.827
Random Effects
σ2 0.02 0.02
τ00 0.02 sub_id 0.02 sub_id
τ11 0.00 sub_id.Session1 0.00 sub_id.Session1
0.00 sub_id.Phase1 0.00 sub_id.Phase1
0.00 sub_id.Session1:Phase1 0.00 sub_id.DMN
  0.00 sub_id.Session1:Phase1
  0.00 sub_id.Session1:DMN
  0.00 sub_id.Phase1:DMN
  0.00 sub_id.Session1:Phase1:DMN
ρ01 -0.04 0.04
-0.31 -0.45
0.04 0.61
  -0.09
  0.63
  -0.37
  -0.29
ICC 0.48  
N 70 sub_id 70 sub_id
Observations 1676 1676
Marginal R2 / Conditional R2 0.015 / 0.489 0.033 / NA



Post-Hoc: Main

Only the valence effect sticks out, so we run a specific post-hoc test to investigate it further.

emmeans(model.mem_correct,  list(pairwise ~Session*valence), by=c("Phase"), adjust = "tukey")
$`emmeans of Session, valence | Phase`
Phase = Early:
 Session valence emmean     SE   df lower.CL upper.CL
 Control neg      0.625 0.0215 90.5    0.582    0.667
 Stress  neg      0.645 0.0206 92.8    0.604    0.686
 Control neu      0.581 0.0215 90.5    0.538    0.624
 Stress  neu      0.601 0.0206 92.8    0.561    0.642

Phase = Late:
 Session valence emmean     SE   df lower.CL upper.CL
 Control neg      0.644 0.0230 87.3    0.598    0.689
 Stress  neg      0.637 0.0228 87.5    0.592    0.683
 Control neu      0.583 0.0230 87.3    0.538    0.629
 Stress  neu      0.582 0.0228 87.5    0.537    0.628

Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$`pairwise differences of Session, valence | Phase`
Phase = Early:
 2                          estimate     SE   df t.ratio p.value
 Control neg - Stress neg  -0.020473 0.0211  126  -0.969  0.7671
 Control neg - Control neu  0.043547 0.0153 1392   2.839  0.0237
 Control neg - Stress neu   0.023124 0.0211  126   1.095  0.6934
 Stress neg - Control neu   0.064020 0.0211  126   3.031  0.0155
 Stress neg - Stress neu    0.043597 0.0153 1392   2.849  0.0230
 Control neu - Stress neu  -0.020423 0.0211  126  -0.967  0.7685

Phase = Late:
 2                          estimate     SE   df t.ratio p.value
 Control neg - Stress neg   0.006374 0.0185  158   0.345  0.9858
 Control neg - Control neu  0.060314 0.0153 1392   3.932  0.0005
 Control neg - Stress neu   0.061059 0.0185  158   3.305  0.0064
 Stress neg - Control neu   0.053940 0.0185  158   2.920  0.0207
 Stress neg - Stress neu    0.054685 0.0153 1392   3.574  0.0021
 Control neu - Stress neu   0.000746 0.0185  158   0.040  1.0000

Degrees-of-freedom method: kenward-roger 
P value adjustment: tukey method for comparing a family of 4 estimates 



Plot: Main
df_task.mem_cor_sum <- summarySEwithin(data=df_task.mem_cor, idvar="sub_id", measurevar="per_cor", withinvars=c("Session","Phase","valence"))
Automatically converting the following non-factors to factors: Phase, valence
plot.mem_corr <- ggplot(df_task.mem_cor_sum, aes(y=per_cor, x=Phase, colour=valence, fill=valence, na.rm = TRUE)) +
  geom_bar(stat="summary", alpha=.5, position=position_dodge2())+
  geom_errorbar(aes(ymin=per_cor-se, ymax=per_cor+se), position=position_dodge(.9),size=1, width=0.45, na.rm=T) +
  scale_y_continuous()+ scale_x_discrete()+
  ggtitle("Picture-Location Recall")+
  ylab("Percent Remembered\n") + 
  ggtheme2 
plot.mem_corr + facet_grid(.~Session)



Post-Hoc: DMN by Phase
emtrends(model.mem_correct_brain, pairwise ~ Phase, var="DMN") 
NOTE: Results may be misleading due to involvement in interactions
$emtrends
 Phase DMN.trend     SE   df lower.CL upper.CL
 Early    0.0112 0.0177 28.0  -0.0250   0.0474
 Late     0.0213 0.0178 28.9  -0.0152   0.0578

Results are averaged over the levels of: Session, valence 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$contrasts
 contrast     estimate     SE   df t.ratio p.value
 Early - Late  -0.0101 0.0252 33.9  -0.399  0.6928

Results are averaged over the levels of: Session, valence 
Degrees-of-freedom method: kenward-roger 
emmip(model.mem_correct_brain, Phase ~ DMN, cov.reduce = range) + scale_color_manual(values=stress_colors) + ggtheme2
NOTE: Results may be misleading due to involvement in interactions



Reaction Time

We first take a look at the reaction time. This analysis is done on a trial by trial basis. We will look at the RT between the stress and control sessions, and also look at the effects of the valence of the images on the reaction time. First we take a look at the distribution of the RT’s to better inform us of which model family would fit best. It appears here that we have a significant effect of valence on reaction times. So participants are faster in responding.

Hist.
hist(df_task.mem$rt)



Models
# Main
model.memory_rt <- glmer(rt_s ~ Session*Phase + Session*valence +Session*Phase*valence + (1+Session*Phase|sub_id),
                         contrasts=list(Session="contr.treatment"),
                        data=df_task.mem,
                        family=Gamma("inverse"),
                       control=glmerControl(calc.derivs=FALSE))
# Brain
model.memory_rt_brain <- glmer(rt_s ~ Session*Phase*DMN + (1+Session*Phase*DMN|sub_id),
                               contrasts=list(Session="contr.treatment"),
                        data=df_task.mem,
                       family=Gamma("identity"),
                       control=glmerControl(calc.derivs=FALSE, optimizer="bobyqa", optCtrl=list(maxfun=100000)))
# HTML Output
asis_output(tab_model(model.memory_rt, model.memory_rt_brain)$knitr)
  rt s rt s
Predictors Estimates CI p Estimates CI p
(Intercept) 1.62 1.60 – 1.63 <0.001 2.19 2.16 – 2.23 <0.001
Session [Stress] 1.00 1.00 – 1.01 0.474 -0.01 -0.04 – 0.03 0.753
Phase1 1.00 0.99 – 1.00 0.038 0.03 0.01 – 0.05 0.001
valence1 1.00 1.00 – 1.00 0.062
Session [Stress] * Phase1 1.00 1.00 – 1.01 0.438 -0.02 -0.05 – 0.01 0.220
Session [Stress] *
valence1
1.00 1.00 – 1.01 0.368
Phase1 * valence1 1.00 1.00 – 1.00 0.195
Session [Stress] * Phase1
* valence1
1.00 1.00 – 1.00 0.935
DMN -0.02 -0.05 – 0.01 0.191
Session [Stress] * DMN 0.03 -0.01 – 0.08 0.146
Phase1 * DMN 0.05 0.02 – 0.08 0.003
(Session [Stress]
Phase1)
DMN
-0.01 -0.05 – 0.04 0.703
Random Effects
σ2 0.07 0.07
τ00 0.00 sub_id 0.01 sub_id
τ11 0.00 sub_id.Session1 0.00 sub_id.Session1
0.00 sub_id.Phase1 0.00 sub_id.Phase1
0.00 sub_id.Session1:Phase1 0.00 sub_id.DMN
  0.00 sub_id.Session1:Phase1
  0.00 sub_id.Session1:DMN
  0.00 sub_id.Phase1:DMN
  0.00 sub_id.Session1:Phase1:DMN
ρ01 -0.01 -0.01
-0.04 -0.06
0.11 -0.96
  0.15
  -0.12
  0.24
  0.23
ICC 0.01  
N 70 sub_id 70 sub_id
Observations 17529 17529
Marginal R2 / Conditional R2 0.000 / 0.011 0.020 / NA



Post-Hoc: Main
emmeans(model.memory_rt,  list(pairwise ~ Session*Phase), by=c("Phase"), adjust = "tukey")
NOTE: Results may be misleading due to involvement in interactions
Note: Use 'contrast(regrid(object), ...)' to obtain contrasts of back-transformed estimates
$`emmeans of Session | Phase`
Phase = Early:
 Session emmean      SE  df asymp.LCL asymp.UCL
 Control  0.475 0.00417 Inf     0.467     0.483
 Stress   0.480 0.00409 Inf     0.472     0.488

Phase = Late:
 Session emmean      SE  df asymp.LCL asymp.UCL
 Control  0.484 0.00425 Inf     0.476     0.493
 Stress   0.485 0.00436 Inf     0.476     0.493

Results are averaged over the levels of: valence 
Results are given on the inverse (not the response) scale. 
Confidence level used: 0.95 

$`pairwise differences of Session | Phase`
Phase = Early:
 2                 estimate      SE  df z.ratio p.value
 Control - Stress -0.004940 0.00455 Inf  -1.085  0.2780

Phase = Late:
 2                 estimate      SE  df z.ratio p.value
 Control - Stress -0.000372 0.00491 Inf  -0.076  0.9396

Results are averaged over the levels of: valence 
Note: contrasts are still on the inverse scale 



Plot: Main
df_task.mem_sum <- summarySEwithin(df_task.mem, measurevar="rt",idvar="sub_id", withinvars= c("Session","Phase","valence"))
Automatically converting the following non-factors to factors: Phase
df_task.mem_sum$run = as.numeric((df_task.mem_sum$Phase))
df_task.mem_sum$valence <- relevel(df_task.mem_sum$valence, "negative")
plot.mem_rt <- ggplot(df_task.mem_sum, aes(x=run, y=rt, colour=valence)) + 
                          geom_line() +
                          geom_errorbar(aes(ymin=rt+se, ymax=rt-se),width=0.2, na.rm=TRUE) + 
                          scale_x_continuous(breaks=c(1,2), labels = c("Early", "Late")) + 
                          ggtheme2  
plot.mem_rt + facet_grid(.~Session)



Post-Hoc: Brain
joint_tests(model.memory_rt_brain, by=c("Session","Phase"))
Session = Control, Phase = Early:
 model term df1 df2 F.ratio p.value
 DMN          1 Inf   1.768  0.1836

Session = Stress, Phase = Early:
 model term df1 df2 F.ratio p.value
 DMN          1 Inf   4.950  0.0261

Session = Control, Phase = Late:
 model term df1 df2 F.ratio p.value
 DMN          1 Inf   7.306  0.0069

Session = Stress, Phase = Late:
 model term df1 df2 F.ratio p.value
 DMN          1 Inf   1.464  0.2264
ggplot(df_task.mem, aes(x=DMN, y=rt_s, colour=Session)) + geom_smooth(method="lm") + ggtheme2 +  facet_grid(.~Phase) + scale_color_manual(values=stress_colors)



Oddball

The oddball data has already been processed, theres not much more we need to do there. Therefore, we can begin with the stats.

d-Prime

Hist.
hist(df_task.odd$dprime)



Models
# Signals
signals=c("", "SN" )
# Run in parallel function
models.odd_dprime <- mcmapply(signals, FUN=function(X){fx.par_model(signal=X, 
                                               dv="dprime",  
                                               iv=ifelse(X=="",  "Session*Run", "1+Session*Run*"), 
                                               re=ifelse(X=="",  "1+Session+Run", paste("1+Session+Run")), 
                                               sub_id="sub_nr", 
                                               fam="lmer", 
                                               data=df_task.odd)}, mc.cores=5)
# Print HTML Output
asis_output(tab_model(models.odd_dprime, dv.labels = c("Signal", "Signal ~ SN"), show.stat =T, show.se=T)$knitr)
  Signal Signal ~ SN
Predictors Estimates std. Error CI Statistic p Estimates std. Error CI Statistic p
(Intercept) 0.40 0.05 0.31 – 0.49 8.58 <0.001 0.34 0.07 0.20 – 0.47 4.92 <0.001
Session [Stress] -0.43 0.06 -0.54 – -0.32 -7.39 <0.001 -0.38 0.09 -0.56 – -0.20 -4.10 <0.001
Run1 0.01 0.03 -0.05 – 0.07 0.38 0.703 0.04 0.06 -0.07 – 0.15 0.69 0.492
Session [Stress] * Run1 -0.04 0.04 -0.12 – 0.05 -0.90 0.369 -0.08 0.08 -0.24 – 0.07 -1.04 0.299
SN 0.05 0.05 -0.04 – 0.15 1.15 0.250
Session [Stress] * SN -0.05 0.06 -0.17 – 0.08 -0.75 0.452
Run1 * SN -0.02 0.04 -0.10 – 0.06 -0.43 0.667
(Session [Stress] * Run1)
* SN
0.03 0.06 -0.08 – 0.15 0.56 0.575
Random Effects
σ2 0.10 0.10
τ00 0.02 sub_nr 0.02 sub_nr
τ11 0.02 sub_nr.Session1 0.02 sub_nr.Session1
0.00 sub_nr.Run1 0.00 sub_nr.Run1
ρ01 0.57 0.58
-0.82 -0.88
N 63 sub_nr 63 sub_nr
Observations 222 222
Marginal R2 / Conditional R2 0.319 / NA 0.317 / NA



Plot: Main
plot.odd_sess <- ggplot(df_task.odd, aes(x=Scan, y=dprime, colour=Scan, fill=Scan)) + 
    geom_violin(alpha=0.5) + 
    geom_boxplot(width=0.1, alpha=0.2) +
    geom_hline(yintercept=0, colour="grey") +
    ggtheme2
plot.odd_sess



Post-Hoc: Brain
joint_tests(models.odd_dprime[[2]], by=c("Session", "Run"))
Session = Control, Run = Early:
 model term df1    df2 F.ratio p.value
 SN           1  87.57   0.328  0.5686

Session = Stress, Run = Early:
 model term df1    df2 F.ratio p.value
 SN           1  85.42   0.118  0.7318

Session = Control, Run = Late:
 model term df1    df2 F.ratio p.value
 SN           1 101.58   1.121  0.2922

Session = Stress, Run = Late:
 model term df1    df2 F.ratio p.value
 SN           1  86.14   0.022  0.8818



Hits

Hist.

We first check the hits. It appears that there is a significant difference in the hit-rate between the two sessions, and between the runs.

hist(df_task.odd$odd_hits)



Models
# Contrasts to investigate
signals=c("", "SN")
# Run in parallel function
models.odd_hits <- mcmapply(signals, FUN=function(X){fx.par_model(signal=X, 
                                               dv="odd_hits",  
                                               iv=ifelse(X=="",  "Session*Run", "1+Session*Run*"), 
                                               re=ifelse(X=="",  "1+Session+Run", paste("1+Session+Run")), 
                                               sub_id="sub_nr", 
                                               fam="lmer", 
                                               data=df_task.odd)}, mc.cores=5)
# Print HTML Output
asis_output(tab_model(models.odd_hits, dv.labels = c("Signal", "Signal ~ SN"), show.stat =T, show.se=T)$knitr)
  Signal Signal ~ SN
Predictors Estimates std. Error CI Statistic p Estimates std. Error CI Statistic p
(Intercept) 20.34 0.69 18.99 – 21.69 29.46 <0.001 20.21 0.95 18.35 – 22.07 21.34 <0.001
Session [Stress] -3.40 0.68 -4.74 – -2.06 -4.97 <0.001 -3.88 1.26 -6.36 – -1.41 -3.08 0.002
Run1 -1.85 0.43 -2.68 – -1.01 -4.34 <0.001 -1.77 0.73 -3.20 – -0.33 -2.42 0.016
Session [Stress] * Run1 0.22 0.57 -0.90 – 1.34 0.38 0.701 1.06 1.11 -1.12 – 3.24 0.95 0.340
SN 0.12 0.59 -1.04 – 1.28 0.20 0.842
Session [Stress] * SN 0.50 0.92 -1.30 – 2.30 0.54 0.587
Run1 * SN -0.07 0.55 -1.14 – 1.00 -0.13 0.900
(Session [Stress] * Run1)
* SN
-0.79 0.83 -2.42 – 0.83 -0.96 0.339
Random Effects
σ2 17.02 17.40
τ00 24.18 sub_nr 24.36 sub_nr
τ11 2.15 sub_nr.Session1 2.17 sub_nr.Session1
1.10 sub_nr.Run1 0.87 sub_nr.Run1
ρ01 -0.46 -0.45
-0.11 -0.11
ICC 0.60 0.59
N 63 sub_nr 63 sub_nr
Observations 222 222
Marginal R2 / Conditional R2 0.126 / 0.649 0.132 / 0.646



Plot: Main
plot.odd_hits <- ggplot(df_task.odd, aes(x=Scan, y=odd_hits, colour=Scan, fill=Scan)) + 
    geom_violin(alpha=0.5) + 
    geom_boxplot(width=0.1, alpha=0.2) +
    ggtheme2
plot.odd_hits 



Post-Hoc: Brain
joint_tests(models.odd_hits[[2]], by=c("Session", "Run")) 
Session = Control, Run = Early:
 model term df1   df2 F.ratio p.value
 SN           1 88.29   0.004  0.9526

Session = Stress, Run = Early:
 model term df1   df2 F.ratio p.value
 SN           1 97.52   0.063  0.8024

Session = Control, Run = Late:
 model term df1   df2 F.ratio p.value
 SN           1 97.12   0.048  0.8266

Session = Stress, Run = Late:
 model term df1   df2 F.ratio p.value
 SN           1 98.67   2.142  0.1465



False Alarms

We also see that they perform more errors. So we have decreased hits, and more errors in the stress session

Models
# MLoop over
signals=c("", "SN")
# Run in parallel function
models.odd_fas <- mcmapply(signals, FUN=function(X){fx.par_model(signal=X, 
                                               dv="odd_FA",  
                                               iv=ifelse(X=="",  "Session*Run", "1+Session*Run*"), 
                                               re=ifelse(X=="",  "1+Session+Run", paste("1+Session+Run")), 
                                               sub_id="sub_nr", 
                                               fam="lmer", 
                                               data=df_task.odd)}, mc.cores=5)
# HTML Output
tab.odd_fas <- tab_model(models.odd_fas, show.se=T, show.stat=T, dv.labels=c("Signal", "Signal ~ SN"))
asis_output(tab.odd_fas$knitr)
  Signal Signal ~ SN
Predictors Estimates std. Error CI Statistic p Estimates std. Error CI Statistic p
(Intercept) 7.40 0.36 6.70 – 8.11 20.60 <0.001 8.08 0.50 7.09 – 9.07 16.03 <0.001
Session [Stress] 1.67 0.43 0.82 – 2.52 3.86 <0.001 0.62 0.72 -0.79 – 2.03 0.86 0.391
Run1 -1.07 0.23 -1.52 – -0.62 -4.65 <0.001 -1.45 0.41 -2.25 – -0.65 -3.54 <0.001
Session [Stress] * Run1 0.31 0.31 -0.30 – 0.93 1.01 0.315 1.17 0.62 -0.05 – 2.38 1.88 0.060
SN -0.58 0.34 -1.24 – 0.08 -1.73 0.083
Session [Stress] * SN 0.95 0.51 -0.05 – 1.95 1.85 0.064
Run1 * SN 0.28 0.30 -0.31 – 0.88 0.93 0.352
(Session [Stress] * Run1)
* SN
-0.74 0.46 -1.64 – 0.16 -1.61 0.107
Random Effects
σ2 5.12 5.54
τ00 4.34 sub_nr 4.12 sub_nr
τ11 1.38 sub_nr.Session1 1.07 sub_nr.Session1
0.23 sub_nr.Run1 0.13 sub_nr.Run1
ρ01 -0.15 -0.24
-0.21 -0.20
ICC 0.47 0.44
N 63 sub_nr 63 sub_nr
Observations 222 222
Marginal R2 / Conditional R2 0.135 / 0.544 0.151 / 0.521



Plot: Main
plot.odd_fas <- ggplot(df_task.odd, aes(x=Scan, y=odd_FA, colour=Scan, fill=Scan)) + 
    geom_violin(alpha=0.5) + 
    geom_boxplot(width=0.1, alpha=0.2) +
    ggtheme2
plot.odd_fas



Post-Hoc: SN by Session
emtrends(models.odd_fas[[2]], pairwise ~ Session, var="SN")
NOTE: Results may be misleading due to involvement in interactions
$emtrends
 Session SN.trend    SE  df lower.CL upper.CL
 Control   -0.582 0.350 142   -1.275     0.11
 Stress     0.366 0.406 149   -0.436     1.17

Results are averaged over the levels of: Run 
Degrees-of-freedom method: kenward-roger 
Confidence level used: 0.95 

$contrasts
 contrast         estimate    SE  df t.ratio p.value
 Control - Stress   -0.948 0.532 193  -1.783  0.0762

Results are averaged over the levels of: Run 
Degrees-of-freedom method: kenward-roger 
joint_tests(models.odd_fas[[2]], by=c("Session"))
Session = Control:
 model term df1    df2 F.ratio p.value
 Run          1 111.50  21.681  <.0001
 SN           1 142.00   2.761  0.0988
 Run:SN       1 144.07   0.800  0.3727

Session = Stress:
 model term df1    df2 F.ratio p.value
 Run          1 111.64  11.243  0.0011
 SN           1 149.25   0.813  0.3688
 Run:SN       1 139.00   1.636  0.2030
plot.sn_fas <- ggplot(df_task.odd, aes(x=SN, y=odd_FA, colour=Session, fill=Session)) + 
  geom_smooth(method="lm", formula="y~x", alpha=0.15) + 
  #geom_point(alpha=0.5)+
  scale_color_manual(values=stress_colors) +  scale_fill_manual(values=stress_colors) + 
  ylab("False Alarms") +
  ggtheme2
plot.sn_fas + facet_grid(~Run)



dPrime by Valence

Now we take a look at the effects of stress and valence on recall. So we do something similar here to what we did before, where we split the positive and negative values, and then merge them into a long data frame(same as we did for the memory task recognition trials).

# Subset the neutral item correct response rates
df_task.odd_pos <- df_task.odd %>% dplyr::select("sub_nr", "Session", "Run", "Scan","dprime_pos", "SN", "ECN", "SN_ECN") %>% unique() %>% dplyr::rename(dprime=dprime_pos) %>% mutate(Valence="Positive")
# Do the same for the negative items
df_task.odd_neg <- df_task.odd %>% dplyr::select("sub_nr", "Session", "Run", "Scan","dprime_neg", "SN", "ECN", "SN_ECN") %>% unique() %>% dplyr::rename(dprime=dprime_neg) %>% mutate(Valence="Negative")
# Bind them into one dataframe
df_task.odd_val <- rbind.data.frame(df_task.odd_pos, df_task.odd_neg)
Models
# Loop over these
signals=c("", "SN")
# Run in parallel function
models.odd_val <- mcmapply(signals, FUN=function(X){fx.par_model(signal=X, 
                                               dv="dprime",  
                                               iv=ifelse(X=="",  "Session*Run*Valence", "1+Session*Run*Valence*"), 
                                               re=ifelse(X=="",  "1+Session+Run", paste("1+Session+Run")), 
                                               sub_id="sub_nr", 
                                               fam="lmer", 
                                               data=df_task.odd_val)}, mc.cores=5)
# Print HTML Output
asis_output(tab_model(models.odd_val, 
                      dv.labels = c("Signal", "Signal ~ SN"),
                      show.stat =T, show.se=T)$knitr)
  Signal Signal ~ SN
Predictors Estimates std. Error CI Statistic p Estimates std. Error CI Statistic p
(Intercept) 0.39 0.05 0.30 – 0.48 8.49 <0.001 0.33 0.07 0.20 – 0.46 4.86 <0.001
Session [Stress] -0.42 0.06 -0.54 – -0.31 -7.37 <0.001 -0.38 0.09 -0.56 – -0.20 -4.16 <0.001
Run1 0.01 0.03 -0.05 – 0.07 0.34 0.736 0.04 0.06 -0.07 – 0.14 0.67 0.505
Valence1 -0.01 0.03 -0.07 – 0.04 -0.48 0.633 0.01 0.05 -0.09 – 0.10 0.12 0.904
Session [Stress] * Run1 -0.03 0.04 -0.12 – 0.05 -0.76 0.449 -0.08 0.08 -0.24 – 0.08 -0.98 0.327
Session [Stress] *
Valence1
0.04 0.04 -0.04 – 0.12 0.91 0.363 0.05 0.07 -0.09 – 0.20 0.73 0.462
Run1 * Valence1 0.03 0.03 -0.02 – 0.09 1.15 0.249 0.01 0.05 -0.09 – 0.11 0.24 0.808
Session [Stress] * Run1 *
Valence1
-0.02 0.04 -0.11 – 0.06 -0.53 0.595 0.03 0.07 -0.11 – 0.18 0.47 0.641
SN 0.05 0.05 -0.04 – 0.14 1.12 0.262
Session [Stress] * SN -0.04 0.06 -0.16 – 0.08 -0.64 0.523
Run1 * SN -0.02 0.04 -0.10 – 0.06 -0.44 0.660
Valence1 * SN -0.02 0.04 -0.09 – 0.05 -0.46 0.644
(Session [Stress] * Run1)
* SN
0.03 0.06 -0.08 – 0.15 0.57 0.569
(Session [Stress]
Valence1)
SN
-0.01 0.05 -0.12 – 0.09 -0.21 0.835
(Run1 * Valence1) * SN 0.02 0.04 -0.05 – 0.09 0.53 0.599
(Session [Stress] * Run1
* Valence1) * SN
-0.05 0.05 -0.15 – 0.06 -0.84 0.400
Random Effects
σ2 0.20 0.20
τ00 0.02 sub_nr 0.02 sub_nr
τ11 0.02 sub_nr.Session1 0.02 sub_nr.Session1
0.00 sub_nr.Run1 0.00 sub_nr.Run1
ρ01 0.59 0.58
-0.86 -0.92
N 63 sub_nr 63 sub_nr
Observations 444 444
Marginal R2 / Conditional R2 0.188 / NA 0.191 / NA



Plot: Main
plot.odd_valence <- ggplot(df_task.odd_val, aes(x=Scan, y=dprime, colour=Scan, fill=Scan)) + 
    geom_violin(alpha=0.5) + 
    geom_boxplot(width=0.1, alpha=0.2) +
    geom_hline(yintercept=0, colour="grey") +
    ggtheme2
plot.odd_valence + facet_grid(. ~ Valence)



Post-Hoc: Brain
joint_tests(models.odd_val[[2]], by=c("Session", "Run")) 
Session = Control, Run = Early:
 model term df1    df2 F.ratio p.value
 Valence      1 259.80   0.211  0.6464
 SN           1  99.13   0.295  0.5882
 Valence:SN   1 259.80   0.002  0.9638

Session = Stress, Run = Early:
 model term df1    df2 F.ratio p.value
 Valence      1 259.80   1.071  0.3017
 SN           1  94.03   0.198  0.6577
 Valence:SN   1 259.80   1.005  0.3171

Session = Control, Run = Late:
 model term df1    df2 F.ratio p.value
 Valence      1 259.80   1.298  0.2556
 SN           1 124.94   1.117  0.2926
 Valence:SN   1 259.80   0.499  0.4808

Session = Stress, Run = Late:
 model term df1    df2 F.ratio p.value
 Valence      1 259.80   0.075  0.7845
 SN           1  95.63   0.004  0.9497
 Valence:SN   1 259.80   0.001  0.9753



Hit+Miss Joint Plot

plot.odd_results <- ggarrange(
  ggarrange(ggarrange(NULL, (plot.odd_sess + xlab("") + labs(color="", fill="") + ylab("dPrime (a.u.)") + theme(axis.text.x=element_blank()) ),
                      NULL, (plot.odd_hits + xlab("") + ylab("Hits (count)")+theme(axis.text.x=element_blank()) ), 
                      NULL, (plot.odd_fas + xlab("") + ylab("False Alarms (count)")+theme(axis.text.x=element_blank()) ), 
                      ncol=6, common.legend = T, legend="bottom", widths=c(0.05, 1, 0.05, 1, 0.05, 1), labels =c("A", "", "B", "", "C")),
  (plot.sn_fas+ylab("False Alarms (count)")+xlab("SN Activity (a.u.)")), nrow=2, legend="bottom", labels=c("", "D")))
plot.odd_results
ggsave("figures/Figure_5_OddBeh.svg", device="svg", dpi =300, width=5, height = 6)

RT

df_task.oddrt <- df_task %>% subset(task==1 & valence==0 & rt!=0) %>% subset(rt>200) 
df_task.oddrt$valence <- (str_split_fixed(df_task.oddrt$stimulus, pattern="_", n =3))[,2]
Models
# Ma
signals=c("", "SN")
models.odd_rts <- mcmapply(signals, FUN=function(X){fx.par_model(signal=X,
                                               dv="rt",
                                               iv=ifelse(X=="",  "Session*Phase", "1+Session*Phase*"),
                                               re=ifelse(X=="",  "1+Session*Phase", paste("1+Session*Phase+", X, sep="")),
                                               sub_id="sub_id",
                                               fam=Gamma("log"),
                                               data=df_task.oddrt)}, mc.cores=5)
the condition has length > 1 and only the first element will be usedthe condition has length > 1 and only the first element will be used
# Print HTML Output
asis_output(tab_model(models.odd_rts, dv.labels = c("Signal", "Signal ~ SN"), show.stat =T, show.se=T)$knitr)
  Signal Signal ~ SN
Predictors Estimates std. Error CI Statistic p Estimates std. Error CI Statistic p
(Intercept) 603.46 5.97 591.87 – 615.27 647.37 <0.001 595.57 8.03 580.03 – 611.53 473.61 <0.001
Session [Stress] 0.97 0.01 0.96 – 0.99 -3.09 0.002 0.97 0.01 0.95 – 1.00 -1.65 0.098
Phase1 0.98 0.01 0.97 – 0.99 -4.09 <0.001 0.99 0.01 0.97 – 1.01 -1.22 0.223
Session [Stress] * Phase1 1.00 0.01 0.98 – 1.01 -0.69 0.492 0.99 0.01 0.96 – 1.01 -1.04 0.299
SN 1.01 0.01 0.99 – 1.03 1.29 0.196
Session [Stress] * SN 1.00 0.01 0.98 – 1.02 -0.27 0.787
Phase1 * SN 0.99 0.01 0.98 – 1.00 -1.41 0.160
(Session [Stress]
Phase1)
SN
1.01 0.01 0.99 – 1.03 0.75 0.455
Random Effects
σ2 0.06 0.06
τ00 0.01 sub_id 0.01 sub_id
τ11 0.00 sub_id.Session1 0.00 sub_id.Session1
0.00 sub_id.Phase1 0.00 sub_id.Phase1
0.00 sub_id.Session1:Phase1 0.00 sub_id.SN
  0.00 sub_id.Session1:Phase1
ρ01 -0.01 -0.01
-0.09 -0.05
-0.10 -0.58
  -0.26
ICC 0.08 0.08
N 70 sub_id 70 sub_id
Observations 11064 11064
Marginal R2 / Conditional R2 0.011 / 0.089 0.013 / 0.092



Post-Hoc: Main
emmeans(models.odd_rts[[1]],  list(pairwise ~Session*Phase), by=c("Phase"), adjust = "tukey")
$`emmeans of Session | Phase`
Phase = Early:
 Session emmean      SE  df asymp.LCL asymp.UCL
 Control  6.381 0.01084 Inf     6.360     6.402
 Stress   6.348 0.01101 Inf     6.327     6.370

Phase = Late:
 Session emmean      SE  df asymp.LCL asymp.UCL
 Control  6.424 0.01155 Inf     6.402     6.447
 Stress   6.401 0.01123 Inf     6.379     6.423

Results are given on the log (not the response) scale. 
Confidence level used: 0.95 

$`pairwise differences of Session | Phase`
Phase = Early:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   0.0330 0.0114 Inf   2.895  0.0038

Phase = Late:
 2                estimate     SE  df z.ratio p.value
 Control - Stress   0.0233 0.0116 Inf   2.001  0.0454

Results are given on the log (not the response) scale. 



Plot: Main
df_task.oddrt_summ <- summarySEwithin(df_task.oddrt,idvar="sub_id", measurevar="rt", withinvars =c("Session", "Phase"))
Automatically converting the following non-factors to factors: Phase
df_task.oddrt_summ$Phase <- as.numeric(as.factor(df_task.oddrt_summ$Phase))
df_task.oddrt_summ$Session <- relevel(df_task.oddrt_summ$Session, "Stress")
ggplot(df_task.oddrt_summ, aes(x=Phase, y=rt, color=Session, fill=Session)) +
    geom_line() + 
    geom_errorbar(aes(ymin=rt-se, ymax=rt+se, color=Session),size=1, width=0.15, na.rm=T)+ 
  ggtheme2 + scale_x_continuous(breaks=c(1,2,3,4,5,6)) 



Post-Hoc: Brain
joint_tests(models.odd_rts[[2]], by=c("Session", "Phase"), adjust="none")
Session = Control, Phase = Early:
 model term df1 df2 F.ratio p.value
 SN           1 Inf   0.002  0.9634

Session = Stress, Phase = Early:
 model term df1 df2 F.ratio p.value
 SN           1 Inf   0.208  0.6484

Session = Control, Phase = Late:
 model term df1 df2 F.ratio p.value
 SN           1 Inf   3.336  0.0678

Session = Stress, Phase = Late:
 model term df1 df2 F.ratio p.value
 SN           1 Inf   0.967  0.3254
Mediation
library(mediation)
Loading required package: mvtnorm
Loading required package: sandwich
mediation: Causal Mediation Analysis
Version: 4.5.0


Attaching package: ‘mediation’

The following object is masked from ‘package:psych’:

    mediate
mediation.med <- lme4::lmer(SN ~ Session*Phase + (1|sub_nr), data=df_task.oddrt, REML=F)
mediation.main <- lme4::lmer(log10(rt) ~ Session*Phase + SN + (1|sub_nr), data=df_task.oddrt, REML=F)
mediation.analysis <- mediate(model.m=mediation.med, model.y=mediation.main, treat ="Session", control.value="Control", mediator = "SN", sims=5000)
treatment and control values do not match factor levels; using Control and Stress as control and treatment, respectively
summary(mediation.analysis)

Causal Mediation Analysis 

Quasi-Bayesian Confidence Intervals

Mediator Groups: sub_nr 

Outcome Groups: sub_nr 

Output Based on Overall Averages Across Groups 

                          Estimate 95% CI Lower 95% CI Upper p-value    
ACME (control)            3.53e-04     3.03e-05         0.00   0.029 *  
ACME (treated)            3.53e-04     3.03e-05         0.00   0.029 *  
ADE (control)            -1.01e-02    -1.38e-02        -0.01  <2e-16 ***
ADE (treated)            -1.01e-02    -1.38e-02        -0.01  <2e-16 ***
Total Effect             -9.75e-03    -1.35e-02        -0.01  <2e-16 ***
Prop. Mediated (control) -3.56e-02    -8.53e-02         0.00   0.029 *  
Prop. Mediated (treated) -3.56e-02    -8.53e-02         0.00   0.029 *  
ACME (average)            3.53e-04     3.03e-05         0.00   0.029 *  
ADE (average)            -1.01e-02    -1.38e-02        -0.01  <2e-16 ***
Prop. Mediated (average) -3.56e-02    -8.53e-02         0.00   0.029 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Sample Size Used: 11064 


Simulations: 5000 

FA by RT

Models
df_task.odd_rt_fa <- df_task.oddrt %>% dplyr::group_by(sub_nr, Session, Phase) %>% dplyr::summarise(rt=mean(rt)) %>% dplyr::rename(Run=Phase) %>% ungroup() %>% merge(., df_task.odd, by=c("sub_nr", "Session", "Run"))
`summarise()` has grouped output by 'sub_nr', 'Session'. You can override using the `.groups` argument.
model.odd_fa_rt <- lmer(rt ~ Session*Run*odd_FA + (1+Session+Run|sub_nr) , 
                        data=df_task.odd_rt_fa, 
                        contrast=list(Session="contr.treatment"), 
                        control=lmerControl(calc.derivs = F, optimizer="bobyqa", optCtrl=list(maxfun=100000)))
asis_output(tab_model(model.odd_fa_rt)$knitr)
  rt
Predictors Estimates CI p
(Intercept) 631.60 596.33 – 666.86 <0.001
Session [Stress] -33.31 -71.26 – 4.64 0.085
Run1 -43.64 -61.64 – -25.65 <0.001
odd_FA -2.74 -6.10 – 0.62 0.110
Session [Stress] * Run1 29.11 2.47 – 55.75 0.032
Session [Stress] * odd_FA 2.20 -1.99 – 6.38 0.304
Run1 * odd_FA 3.16 0.93 – 5.40 0.005
(Session [Stress] * Run1)
* odd_FA
-3.69 -6.69 – -0.69 0.016
Random Effects
σ2 817.56
τ00 sub_nr 8707.72
τ11 sub_nr.Session1 803.41
τ11 sub_nr.Run1 123.85
ρ01 0.11
-0.66
ICC 0.92
N sub_nr 63
Observations 222
Marginal R2 / Conditional R2 0.049 / 0.920
check_model(model.odd_fa_rt)
`guides(<scale> = FALSE)` is deprecated. Please use `guides(<scale> = "none")` instead.

#Gaus 2670 #GausLog 3336.29 # Gamma 7770 #Gamma Log
Post-Hoc
joint_tests(model.odd_fa_rt, by=c("Session", "Run"), adjust="none")
Session = Control, Run = Early:
 model term df1    df2 F.ratio p.value
 odd_FA       1 109.60   0.033  0.8571

Session = Stress, Run = Early:
 model term df1    df2 F.ratio p.value
 odd_FA       1 107.68   0.355  0.5527

Session = Control, Run = Late:
 model term df1    df2 F.ratio p.value
 odd_FA       1 116.29   9.712  0.0023

Session = Stress, Run = Late:
 model term df1    df2 F.ratio p.value
 odd_FA       1 107.94   0.000  0.9934
Plot
emmip(model.odd_fa_rt, Session + Run ~ odd_FA, cov.reduce = range)+ ggtheme2# + scale_color_manual(values=stress_colors) 

rcorr(df_task.odd_rt_fa$rt, df_task.odd_rt_fa$odd_FA)
      x     y
x  1.00 -0.07
y -0.07  1.00

n= 222 


P
  x      y     
x        0.2951
y 0.2951       
plot.odd_fa_rt <- ggplot(df_task.odd_rt_fa, aes(x=odd_FA, y=rt)) + geom_smooth(method="lm" )
plot.odd_fa_rt + facet_grid(Session~Run)

5 System Info

sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-conda_cos6-linux-gnu (64-bit)
Running under: CentOS Linux 7 (Core)

Matrix products: default
BLAS/LAPACK: /home/cogaff/raytut/.conda/envs/r_env/lib/R/lib/libRblas.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] parallel  stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] mediation_4.5.0   sandwich_3.0-1    mvtnorm_1.1-2     doSNOW_1.0.19     snow_0.4-4        iterators_1.0.13  foreach_1.5.1     future_1.21.0     kableExtra_1.3.4 
[10] extrafont_0.17    stargazer_5.2.2   car_3.0-11        carData_3.0-4     sjPlot_2.8.10     ggpubr_0.4.0      emmeans_1.6.2-1   performance_0.8.0 jtools_2.1.3     
[19] optimx_2021-6.12  afex_1.0-1        lmerTest_3.1-3    lme4_1.1-27.1     Matrix_1.4-0      corrplot_0.90     ppcor_1.1         MASS_7.3-54       corrr_0.4.3      
[28] Hmisc_4.6-0       Formula_1.2-4     survival_3.2-13   lattice_0.20-45   psycho_0.6.1      psych_2.1.6       zoo_1.8-9         data.table_1.14.2 janitor_2.1.0    
[37] hablar_0.3.0      broom_0.7.9       plyr_1.8.6        forcats_0.5.1     stringr_1.4.0     dplyr_1.0.7       purrr_0.3.4       readr_2.1.1       tidyr_1.1.3      
[46] tibble_3.1.3      ggplot2_3.3.5     tidyverse_1.3.1   readxl_1.3.1      knitr_1.36       

loaded via a namespace (and not attached):
  [1] utf8_1.2.2          tidyselect_1.1.1    htmlwidgets_1.5.4   grid_3.6.1          lpSolve_5.6.15      munsell_0.5.0       codetools_0.2-18    effectsize_0.4.5   
  [9] withr_2.4.2         colorspace_2.0-2    highr_0.9           rstudioapi_0.13     robustbase_0.93-8   ggsignif_0.6.3      Rttf2pt1_1.3.9      listenv_0.8.0      
 [17] labeling_0.4.2      mnormt_2.0.2        bit64_4.0.5         farver_2.1.0        datawizard_0.2.1    parallelly_1.27.0   vctrs_0.3.8         generics_0.1.0     
 [25] xfun_0.25           R6_2.5.0            assertthat_0.2.1    scales_1.1.1        vroom_1.5.7         nnet_7.3-16         gtable_0.3.0        globals_0.14.0     
 [33] qqplotr_0.0.5       rlang_0.4.11        systemfonts_1.0.2   splines_3.6.1       rstatix_0.7.0       extrafontdb_1.0     checkmate_2.0.0     reshape2_1.4.4     
 [41] abind_1.4-5         modelr_0.1.8        backports_1.4.1     tools_3.6.1         ellipsis_0.3.2      RColorBrewer_1.1-2  ggridges_0.5.3      Rcpp_1.0.7         
 [49] base64enc_0.1-3     rpart_4.1-15        cowplot_1.1.1       haven_2.4.3         ggrepel_0.9.1       cluster_2.1.2       fs_1.5.0            magrittr_2.0.1     
 [57] openxlsx_4.2.4      reprex_2.0.1        tmvnsim_1.0-2       packrat_0.7.0       sjmisc_2.8.7        hms_1.1.0           evaluate_0.14       xtable_1.8-4       
 [65] pbkrtest_0.5.1      rio_0.5.27          sjstats_0.18.1      jpeg_0.1-9          gridExtra_2.3       ggeffects_1.1.1     compiler_3.6.1      crayon_1.4.1       
 [73] minqa_1.2.4         htmltools_0.5.2     mgcv_1.8-38         tzdb_0.1.2          lubridate_1.7.10    DBI_1.1.1           sjlabelled_1.1.8    dbplyr_2.1.1       
 [81] see_0.6.4           boot_1.3-28         cli_3.0.1           insight_0.14.4      pkgconfig_2.0.3     numDeriv_2016.8-1.1 foreign_0.8-71      xml2_1.3.2         
 [89] svglite_2.0.0       webshot_0.5.2       estimability_1.3    rvest_1.0.1         snakecase_0.11.0    digest_0.6.27       parameters_0.14.0   rmarkdown_2.11     
 [97] cellranger_1.1.0    htmlTable_2.3.0     curl_4.3.2          nloptr_1.2.2.2      lifecycle_1.0.0     nlme_3.1-153        jsonlite_1.7.2      viridisLite_0.4.0  
[105] fansi_0.5.0         pillar_1.6.2        fastmap_1.1.0       httr_1.4.2          DEoptimR_1.0-9      glue_1.4.2          bayestestR_0.10.5   zip_2.2.0          
[113] png_0.1-7           pander_0.6.4        bit_4.0.4           stringi_1.7.3       latticeExtra_0.6-29
LS0tCnRpdGxlOiAiTGFyZ2UgU2NhbGUgTmV0d29yayBCYWxhbmNlIFVuZGVyIFN0cmVzcyBhbmQgUmVhbC1saWZlIEFmZmVjdGl2ZSBTdHJlc3MgUmVhY3Rpdml0eSIKYXV0aG9yOiAiUmF5eWFuIFR1dHVuamkiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkLSViLSVZJylgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZmlnX2hlaWdodDogNgogICAgZmlnX3dpZHRoOiA3CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IG5vCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIEludHJvZHVjdGlvbiB7LX0KVGhlIGZvbGxvd2luZyBjb2RlIGlzIHNwZWNpZmljIHRvIHRoZSB0YXNrIHJlbGF0ZWQgZk1SSSB0YXNrIGFuYWx5c2lzIG9mIHRoZSBTdHJlc3MgUmVzaWxpZW5jZSBhbmQgdGhlIEJyYWluIGluIE1lZGljYWwgU3R1ZGVudHMgKFNUUkFJTi1NRCkgc3R1ZHkuIERldGFpbHMgb2YgdGhlIHN0dWR5IGNhbiBiZSBmb3VuZCBpbiBhbiBlYXJsaWVyIFtwdWJsaWNhdGlvbl0oaHR0cHM6Ly93d3cuYmlvcnhpdi5vcmcvY29udGVudC8xMC4xMTAxLzIwMjEuMDYuMjkuNDUwMzYwdjIpLiBJbiBzaG9ydCwgdGhlIHN0dWR5IGNvbnNpc3RlZCBvZiBhIHdpdGhpbiBzdWJqZWN0IGRlc2lnbiBleGFtaW5pbmcgcmVhbC1saWZlIHN0cmVzcyBleHBvc3VyZSB3aXRoICoqRWNvbG9naWNhbCBNb21lbnRhcnkgQXNzZXNzbWVudHMoRU1BKSoqIG1lYXN1cmVzLCBhbmQgYW4gZk1SSSBzdHJlc3MgZXhwb3N1cmUgdXNpbmcgdGhlICoqU29jaWFsbHkgRXZhbHVhdGVkIENvbGQgUHJlc3NvciB0YXNrKFNFQ1BUKSoqLiBUaGUgbWFpbiBhaW0gb2YgdGhlIHN0dWR5IGFzIHdob2xlIGlzIHRvIGxpbmsgY2hhbmdlcyBpcyBsYXJnZSBzY2FsZSBicmFpbiBuZXR3b3JrcyB1bmRlciBzdHJlc3MgdG8gcmVhbC1saWZlIHN0cmVzcyBhbmQgcmVzaWxpZW5jZSBtZWFzdXJlcy4gRGV0YWlscyBvZiB0aGUgcmVhbC1saWZlIHN0cmVzcyBwcm9jZWR1cmUgY2FuIGJlIGZvdW5kIGluIHRoZSBwcmV2aW91c2x5IG1lbnRpb25lZCBwdWJsaWNhdGlvbi4gRHVyaW5nIHRoZSBmTVJJIHNlc3Npb24sIHBhcnRpY2lwYW50cyBlbmdhZ2VkIGluIHRocmVlIHRhc2tzLiBUaGUgZk1SSSB0YXNrcyBhcmUgZGVzaWduZWQgdG8gYWN0aXZhdGUgc3BlY2lmaWMgcGFydHMgb2YgdGhlIGJyYWluLiBQcmltYXJpbHksIHRoZSAqKkV4ZWN1dGl2ZSBDb250cm9sIChFQ04pKiosICoqRGVmYXVsdCBNb2RlIChETU4pKiosIGFuZCAqKlNhbGllbmNlIChTTikqKiBuZXR3b3Jrcy4gVGhlIEVDTiB0YXNrIGlzIGEgMi1CYWNrIHdoZXJlIHBhcnRpY2lwYW50cyByZXNwb25kIGV2ZXJ5IHRpbWUgdGhleSBzZWUgMi1CYWNrIG51bWJlci4gVGhlIERNTiB0YXNrIGlzIGFuIGFzc29jaWF0aXZlIHJldHJpZXZhbCB0YXNrLiBGb3IgdGhpcyB0YXNrLCBwYXJ0aWNpcGFudHMgd2VyZSBzaG93biBpbWFnZXMgdGhhdCBtb3ZlZCB0byAxIG9mIGZvdXIgY29ybmVycyBvZiB0aGUgc2NyZWVuIG91dHNpZGUgdGhlIHNjYW5uZXIuIFRoZXkgd2VyZSB0aGVuIGFza2VkIHRvIGluZGljYXRlIHdoZXJlIHRoZXkgc2F3IHRoZSBpbWFnZXMgdXNpbmcgYnV0dG9uIHByZXNzZXMgaW4gdGhlIHNjYW5uZXIuIFRoZSB0aGlyZCBhbmQgZmluYWwgdGFzayB0aGF0IHRhcmdldGVkIHRoZSBTTiB3YXMgYW4gZW1vdGlvbmFsIG9kZGJhbGwuIEZvciB0aGlzIHRhc2ssIHBhcnRpY2lwYW50cyBoYWQgdG8gcmVzcG9uZCB0byBhIHN0cmVhbSBvZiBmYWNlcyB3aGVuZXZlciBhIG5vdmVsIGZhY2Ugd2l0aCBhbiBlbW90aW9uYWwgZXhwcmVzc2lvbiB3YXMgcHJlc2VudGVkLiBJbiBhZGRpdGlvbiB0byB0aGUgYWN0dWFsIHRhc2tzIGFuZCB0aGVpciBjb250cmFzdHMsIHdlIGFsc28gY29sbGVjdCBwZXJpcGhlcmFsIHBoeXNpb2xvZ2ljYWwgZGF0YS4gVGhpcyBpbmNsdWRlcwoKICAtIEhlYXJ0IFJhdGUKICAtIFNraW4gQ29uZHVjdGFuY2UKICAtIFNhbGl2YXJ5IENvcnRpc29sCgpUaGVzZSBtZWFzdXJlcyB3ZXJlIHVzZWQgdG8gdmFsaWRhdGUgb3VyIGxhYm9yYXRvcnkgc3RyZXNzIGluZHVjdGlvbiBwcm9jZWR1cmUuIEluIHRoaXMgbm90ZWJvb2ssIHdlIHZhbGlkYXRlIHRoZSBzdHJlc3MgaW5kdWN0aW9uIHByb2NlZHVyZXMgdXNpbmcgdGhlIGFib3ZlIGhlYXJ0IHJhdGUgYW5kIHNhbGl2YSBkYXRhLiBXZSBhZGRpdGlvbmFsbHkgZGVyaXZlIGEgbGFiLWJhc2VkIHN0cmVzcyByZWFjdGl2aXR5IG1lYXN1cmUgZnJvbSB0aGUgc2FsaXZhcnkgY29ydGlzb2wgcmVzcG9uc2UgdG8gc3RyZXNzIGR1cmluZyB0aGUgU0VDUFQuIFdlIGFsc28gZGVyaXZlIGEgbWVhc3VyZSBmcm9tIHRoZSByZWFsLWxpZmUgc3RyZXNzIGRhdGEgdGhhdCByZWZsZWN0cyBzdHJlc3MgcmVhY3Rpdml0eS9yZXNpbGllbmNlIGluIGRhaWx5IGxpZmUuIEJvdGggdGhlIGxhYiBzdHJlc3MgbWVhc3VyZSwgYW5kIHRoZSByZWFsLWxpZmUgc3RyZXNzIG1lYXN1cmUgY2FuIHRoZW4gYmUgdXNlZCBpbiBzdWJzZXF1ZW50IGFuYWx5c2lzIG9mIGZNUkkgcmVsYXRlZCBhY3Rpdml0eSBhbmQgb3ZlcmFsbCB0YXNrIHBlcmZvcm1hbmNlIGluIHRoZSBjb3JyZXNwb25kaW5nIHNlY3Rpb25zIGJlbG93LiBJbiBvcmRlciB0byByZXBsaWNhdGUgdGhlc2UgYW5hbHlzZXMsIHRoZSBiZWxvdyBsaWJyYXJpZXMgYXJlIHVzZSwgaW4gYWRkaXRpb24gdG8gYSBmaWxlIHdpdGggY3VzdG9tIGZ1bmN0aW9ucyBzdXBwbGllZCBpbiB0aGUgcmVwb3NpdG9yeS4gCgoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHNldHVwPVRSVUV9CgpsaWJyYXJ5KGtuaXRyKQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZT1UUlVFLCByZXN1bHRzPSdzaG93JywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY29tbWVudD1OQSwgZWNobz1ULCB0aWR5PVRSVUUsIGNvbmNvcmRhbmNlPVRSVUUsIGF1dG9kZXA9VFJVRSkKb3B0aW9ucyhrbml0ci50YWJsZS5mb3JtYXQgPSAiaHRtbCIsIGJvb2t0YWJzPVRSVUUpIAoKI0NsZWFuaW5nIExpYnMKbGlicmFyeShyZWFkeGwpICAgICAgICMgUmVhZCBleGNlbCBzaGVldHMKbGlicmFyeSh0aWR5dmVyc2UpICAKbGlicmFyeShwbHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGJyb29tKSAgICAgICAgICMgdGlkeSBmdW5jdGlvbnMKbGlicmFyeSAoaGFibGFyKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeSh6b28pCgojIEJhc2ljIFN0YXRzCmxpYnJhcnkgKHBzeWNoKSAgICAgICAjIE5pY2UgZGVzY3JpcHRpdmVzIGFuZCBzY2FsaW5nCmxpYnJhcnkgKHBzeWNobykgICAgICAjIFdlIHVzZSB0aGUgZFByaW1lIFRvb2wKbGlicmFyeShIbWlzYykgICAgICAgICMgR2lybCBJIGRvbnQgZXZlbnQga25vdwpsaWJyYXJ5KGNvcnJyKSAgICAgICAgIyBDb3JyZWxhdGlvbgpsaWJyYXJ5KHBwY29yKSAgICAgICAgIyBQYXJ0aWFsIENvcnJlbGF0aW9uCmxpYnJhcnkoY29ycnBsb3QpICAgICAjIENvcnJlbGF0aW9uIG1hdHJpeCBwbG90dGluZwojTGluZWFyIE1vZGVsaW5nCmxpYnJhcnkobG1lclRlc3QpICAgICAjIE1haW4gTWl4ZWQgTW9kZWxzCmxpYnJhcnkoYWZleCkgICAgICAgICAjIEFkdmFuY2VkIE9wdGlvbnMgTWl4ZWQgTW9kZWxzCmxpYnJhcnkob3B0aW14KSAgICAgICAjIE9wdGltaXplciBmb3IgTU1zCmxpYnJhcnkoanRvb2xzKSAgICAgICAjIFVzZXMgc3VtbSBmdW5jdGlvbiBmb3IgcmVhZGFibGUgbW9kZWxzCmxpYnJhcnkocGVyZm9ybWFuY2UpICAjIE1vZGVsIERpYWdub3N0aWNzCmxpYnJhcnkoZW1tZWFucykgICAgICAjIHVzZWQgZm9yIGZvbGxvdy11cCB0ZXN0cyBvbiBsbWVycwojUGxvdHRpbmcKbGlicmFyeShnZ3Bsb3QyKSAgICAgICMgU3RhbmRhcmQgcGxvdHRpbmcKbGlicmFyeShnZ3B1YnIpICAgICAgICMgQXJyYW5nZSBwbG90cwpsaWJyYXJ5KHNqUGxvdCkgICAgICAgIyBQbG90IHJlZ3Jlc3Npb25zIGFuZCBsbWVyCmxpYnJhcnkoY2FyKSAgICAgICAgICAjIEkgdXNlIHRoZSBxcVBsb3QgZnVuY3Rpb24gaGVyZQoKIyBGb250cyBhbmQgQXN0aGV0aWNzCmxpYnJhcnkoc3RhcmdhemVyKQpsaWJyYXJ5KGV4dHJhZm9udCkKbGlicmFyeShrYWJsZUV4dHJhKQoKIyBGdW5jdGlvbnMgYW5kIGNvcmVzCmxpYnJhcnkoZnV0dXJlKSAgICAgICAjIFBhcmFsbGVsIFByb2Nlc3NpbmcKbGlicmFyeShmb3JlYWNoKSAgICAgICMgUGFyYWxsZWwgZm9yIGVhY2ggZnVuY3RpbnMKbGlicmFyeShwYXJhbGxlbCkKbGlicmFyeShkb1NOT1cpICAgICAgICMgZG8gZnVuY3Rpb24gb3ZlciBjb3Jlcwpzb3VyY2UoImZ1bmN0aW9ucy5SIikgIyBDdXN0b20gRnVuY3Rpb25zCgojIE1ha2Ugc3VyZSBsbWVyIGNvbnRyYXN0cyBhcmUgc2V0IHRvIHN1bSAwCm9wdGlvbnMoY29udHJhc3RzPWMoImNvbnRyLnN1bSIsICJjb250ci5wb2x5IikpCgojIEFzc2lnbiBDb3JlcyBmb3IgUGFyYWxsZWwgcHJvY2Vzc2luZwpuY29yZXMgPC0gYXMubnVtZXJpYyhhdmFpbGFibGVDb3JlcygpKS0xCgojIExvYWQgZm9udHMKI2ZvbnRfaW1wb3J0KCkKbG9hZGZvbnRzKGRldmljZT0icGRmIikKCiMgVGhlbWVzIHVzZWQgZm9yIGdncGxvdHMKZ2d0aGVtZTEgPC0gdGhlbWUgKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTYpLAogICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiwgaGp1c3Q9MC41KSwKICAgICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ0cmFuc3BhcmVudCIpLAogICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2xpbmUoc2l6ZT0zKSwKICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYWxpY2VibHVlIikpCmdndGhlbWUyIDwtIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTEsIGZhbWlseT0iQXJpYWxNVCIpLAogICAgICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDEsIGNvbG91ciA9ICJncmV5IiksCiAgICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0idHJhbnNwYXJlbnQiKSwKICAgICAgICAgICAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvciA9IE5BKSwgIyBiZyBvZiB0aGUgcGxvdAogICAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG91cj0iZ3JleTk1IiksCiAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5NSIpKSAKZm1yaV9jb2xvcnMgPC0gYygiIzAwQkZDNCIsICIjN0NBRTAwIiwgIiNGODc2NkQiLCAiIzAwQjhFNyIsICIjMENCNzAyIiwgIiNFNjg2MTMiICkgIyBETU4sIEVDTiwgU04sIEVhcmx5IHRoZW4gTGF0ZQpzdHJlc3NfY29sb3JzIDwtICBjKCIjMDBCRkM0IiwgICIjRjg3NjZEIiwgIiM3Q0FFMDAiLCIjMDBCOEU3IiwgIiNFNjg2MTMiKSAgICAgICAgICAgICAgIApgYGAKCiMgUmVhbC1saWZlIFN0cmVzcwpXZSBmaXJzdCBzdGFydCB3aXRoIHRoZSBzdHJlc3MgaW5kdWN0aW9uIGluIHJlYWwgbGlmZSwgc2luY2UgdG8gc29tZSBleHRlbnQgdGhpcyBpcyBhIHJlcGxpY2F0aW9uIG9mIHByZXZpb3VzbHkgZG9uZSBhbmFseXNlcy4gSGVyZSwgd2UgdXNlZCBhbiBleGFtIGFuZCBjb250cm9sIHdlZWsgYXMgc3RyZXNzb3IgdG8gc2VlIGl0cyBpbXBhY3Qgb24gbW9vZCBhbiBwaHlzaW9sb2d5LiBUaGlzIHdhcyBkb25lIHByaW9yIHRvIGFueSBzY2FubmluZywgYW5kIHlvdSBjYW4gZmluZCBvdXQgbW9yZSBkZXRhaWxzIGluIHRoZSBbcHVibGljYXRpb25dKGh0dHBzOi8vd3d3LmJpb3J4aXYub3JnL2NvbnRlbnQvMTAuMTEwMS8yMDIxLjA2LjI5LjQ1MDM2MHYyKS4gSW4gc2hvcnQsIHdlIGZvdW5kIHRoYXQgb3VyIHN0cmVzcyB3ZWVrcyByZXN1bHQgaW4gaW5jcmVhc2VkIHN1YmplY3RpdmUgc3RyZXNzLCBhbmQgdGhhdCBhZmZlY3QgYW5kIHBoeXNpb2xvZ3kgYm90aCBjaGFuZ2UgaW4gcmVsYXRpb24gdG8gc3RyZXNzIGV4cG9zdXJlLCBhbmQgc3ViamVjdGl2ZSBzdHJlc3MgcmVwb3J0cy4gT3VyIHByaW1hcnkgZ29hbCBmb3IgdGhlIHNha2Ugb2YgdGhlIGN1cnJlbnQgcHJvamVjdCBpcyB0byBkZXJpdmUgYSBtZWFzdXJlIG9mIHN0cmVzcyByZWFjdGl2aXR5IGluIHJlYWwgbGlmZSB0aGF0IHdlIGNhbiB1c2UgYXMgYSBmaXhlZCBlZmZlY3QgaW4gb3VyIGZNUkkgYW5hbHlzZXMuIFdlIHNob3VsZCBiZSBhYmxlIHRvIHVzZSB0aGlzIG1lYXN1cmUgdG8gbGluayBlZmZlY3RzIG9mIHJlYWwgbGlmZSB0byB0aGUgbGFiLCB0byBmTVJJIHRhc2sgcGVyZm9ybWFuY2UsIG9yIHRvIGZNUkkgdGFzayByZWxhdGVkIGFjdGl2aXR5IGFuZCBtb3N0IGltcG9ydGFudGx5IGxhcmdlIHNjYWxlIG5ldHdvcmsgYmFsYW5jZS4gCgpUbyB0aGlzIGVuZCwgd2UgZG8gYW4gaW50ZXJwcmV0YXRpb24gb2YgdGhlIHJlc2lkdWFsIGJhc2VkIHJlZ3Jlc3Nvciwgd2l0aCBzdWJqZWN0aXZlIHN0cmVzcyBhcyBvdXIgZXhwb3N1cmUgbWVhc3VyZXMsIGFuZCBwb3NpdGl2ZSBhZmZlY3QgYXMgb3VyIHJlc2lsaWVuY2UgY29tcG9uZW50LiBUaGlzIGlzIGJhc2VkIG9uIGEgZmV3IGRpZmZlcmVudCBzdHVkaWVzIChSYWZhZWwgS2FsaXNjaCdzIHdvcmssIGFuZCBzb21lIGZyb20gU2FubmUgQm9paikuIFdlIGNvbnRlbXBsYXRlZCB1c2luZyBzb21ldGhpbmcgbGlrZSBlbW90aW9uYWwgaW5lcnRpYSBhbmQgdGhlIGluc3RhYmlsaXR5LCBidXQgdGhlc2UgbWVhc3VyZXMgYXJlIG9ubHkgdXNlZnVsIGZvciBiZXR3ZWVuIHN1YmplY3QgZGVzaWducywgcmF0aGVyIHRoYW4gd2l0aGluLiAKCiMjIERhdGEKV2UgbG9hZCBpbiB0aGUgZmlsZSB0aGF0IHdlIGRlcml2ZSBpbiBvdXIgcGFwZXIgbWVudGlvbmVkIGFib3ZlLiBUaGlzIGNvbnNpc3RzIG9mIHByb2Nlc3NlZCBFTUEgaXRlbXMgZm9yIHN1YmplY3Qgc3RyZXNzIGR1cmluZyBhIHdlZWsgd2l0aCBhbiBleGFtIGFuZCBhbm90aGVyIHdlZWsgd2l0aG91dCBhbiBleGFtIChJRS4gU3RyZXNzIGFuZCBDb250cm9sIHdlZWtzIHJlc3BlY3RpdmVseSkuIEFsbCBkYXRhIGNsZWFuaW5nIGhhcyBhbHJlYWR5IGJlZW4gcGVyZm9ybWVkLCBzbyB3ZSBuZWVkIG1pbmltYWwgcHJvY2Vzc2luZyBhdCB0aGlzIHN0YWdlLiBUaGUgZnVsbCBkZXRhaWxzIG9mIHRoZSBwcm9jZXNzaW5nIHBpcGVsaW5lIHRoYXQgd2FzIHVzZWQgdG8gZ2VuZXJhdGUgdGhpcyBkYXRhIGNhbiBiZSBmb3VuZCBpbiBvdXIgcHJldmlvdXMgc3R1ZHksIHdpdGggdGhlIGFzc29jaWF0ZWQgbm90ZWJvb2sgbWFkZSBhdmFpbGFibGUgb24gW0dpdEh1Yl0oaHR0cHM6Ly9yYXl0dXQuZ2l0aHViLmlvL0RldGVjdGluZ1N0cmVzcy8pLiBBbGwgd2UgbmVlZCB0byBkbyBpcyBsb2FkIHRoZSBkYXRhLCBhbmQgZG8gc29tZSBzaW1wbGUgcmV0eXBpbmcuCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiMgSW1wb3J0IERhdGEgPSBSZXR5cGUKZGZfRU1BIDwtIHJlYWQuY3N2MigiZGF0YS9FTUFfQ2xlYW5fQW5vbi5jc3YiLCBzZXAgPSAiLCIpCmRmX0VNQSA8LSBkZl9FTUEgJT4lIHJldHlwZSgpICMlPiUgcHJpbnQoKQpkZl9FTUEkd2Vla190eXBlIDwtIGRmX0VNQSR3ZWVrX3R5cGUKZGZfRU1BJFdlZWtfVHlwZSA8LSBmYWN0b3IoZGZfRU1BJHdlZWtfdHlwZSwgbGV2ZWxzPWMoMCwxKSwgbGFiZWxzPWMoIkNvbnRyb2wiLCAiU3RyZXNzIikpCmBgYApXZSBhbHNvIHdhbnQgdG8gZGljaHRvbW9pemUgb3VyIHN1YmplY3RpdmUgc3RyZXNzIGxldmVscy4gV2UgZG8gdGhpcyBieSBhc3Nlc3NpbmcgdGhlIG92ZXJhbGwgc3ViamVjdGl2ZSBzdHJlc3MsIGFuZCBkZXRlcm1pbmluZyBzdWJqZWN0LWxldmVsIG1lYW5zLiBJZiB0aGUgc3RyZXNzIGlzIGhpZ2hlciB0aGF0IHRoZSBtZWFuLCB0aGVuIHdlIGdldCBhIHN0cmVzcyBzaXR1YXRpb24uIElmIGl0IGlzIGxvd2VyLCB0aGVuIHdlIGdldCBhIG5vIHN0cmVzcyBzaXR1YXRpb24uCmBgYHtyfQpkZl9FTUEgPC0gZGZfRU1BICU+JSBkcGx5cjo6Z3JvdXBfYnkoY2FzdG9yX3JlY29yZF9pZCkgJT4lIGRwbHlyOjptdXRhdGUoc3NfdG90PShldmVudF90b3QrYWN0aXZpdHlfdG90K3NvY2lhbF90b3QpLCBzc190b3RfYz1zY2FsZShzc190b3QsY2VudGVyPVRSVUUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3NfdG90X209bWVhbihzc190b3RfYywgbmEucm09VFJVRSksIHNzX3RvdF9iaW49ZmFjdG9yKGlmZWxzZShzc190b3RfYz5zc190b3RfbSwgIlN0cmVzcyIsICJOb24tU3RyZXNzIikpICkgJT4lIHVuZ3JvdXAoKSAKZGZfRU1BJG1lYW5fc3RyZXNzX3ogPC0gc2NhbGUoZGZfRU1BJG1lYW5fc3RyZXNzLCBjZW50ZXI9VFJVRSwgc2NhbGU9VCkKCmBgYApXZSBhZGRpdGlvbmFsbHkgd2FudCB0byBjb21lIHVwIHdpdGggYSBtZWFzdXJlIGZyb20gdGhlc2UgRU1BIHdlZWtzIHRoYXQgY2FuIGJlIHJlbGF0ZWQgdG8gbmV1cm90aWNpc20gb3IgZGVwcmVzc2l2ZSBwZXJzb25hbGl0eSB0byBtYWtlIHN1cmUgdGhhdCB3aGF0ZXZlciBtZWFzdXJlIHdlIGRlcml2ZSBpcyBhY3R1YWxseSB2YWxpZCBhbmQgcmVsYXRlZCB0byBhbiBhbHJlYWR5IGVzdGFibGlzaGVkIG1lYXN1cmUgb2Ygc3RyZXNzIHNlbnNpdGl2aXR5LgpgYGB7cn0KZGZfcHN5Y2ggPC0gcmVhZC5jc3YyKCIvcHJvamVjdC8zMDEzMDY4LjAyL3N0YXRzL0VNQS9RdWVzdGlvbm5haXJlcy5jc3YiLCBzZXA9IiwiKSAlPiUgZHBseXI6OnJlbmFtZShzdWJfaWQ9Y2FzdG9yX3JlY29yZF9pZCkKYGBgCgojIyBTdGF0aXN0aWNzCgojIyMgUHJpbWFyeSBNb2RlbHM6IERhaWx5IGxpZmUgZGlmZmVyZW5jZXMgey19CldlIGZpcnN0IG5lZWQgdG8gZ2V0IHRoZSBtYWluIG1vZGVscyB3aGVyZSB3ZSBsb29rIGF0IHRoZSBkaWZmZXJlbmNlcyBpbiBzdWJqZWN0aXZlIHN0cmVzcyAoU1MpIGFuZCBwb3NpdGl2ZSBhZmZlY3QgKFBBKSBiZXR3ZWVuIHRoZSBjb250cm9sIGFuZCBzdHJlc3Mgd2Vla3MuIFdlIHVzZSBtaXhlZCBlZmZlY3RzIG1vZGVscywgd2l0aCByYW5kb20gc2xvcGVzIGFuZCBpbnRlcmNlcHRzIGZvciBlYWNoIHN1YmplY3QuIFRoaXMgYWxsb3dzIHVzIHRvIGFjdHVhbGx5IGdldCBzdWJqZWN0IGxldmVsIGZpeGVkIGVmZmVjdHMgZm9yIHRoZSB3ZWVrIHR5cGUuIEl0cyBzaW1pbGFyIHRvIGRvaW5nIGluZGl2aWR1YWwgcmVncmVzc2lvbnMgZm9yIGVhY2ggc3ViamVjdCB0byBnZXQgdGhlIEJldGFzIGZvciBlYWNoIG9uZS4gVGhlc2UgQmV0YXMgYXJlIHVzZWQgaW4gdGhlIG5leHQgc3RhZ2UuIE5vdGUgdGhhdCB0aGUgcmVzdWx0cyBvZiB0aGVzZSBtb2RlbCBhcmUgY291bnRlciBpbnR1aXRpdmUgYmVjYXVzZSB0aGUgc3ViamVjdCBsZXZlbCBmaXhlZCBlZmZlY3RzIHdlIGZvciB3ZWVrIHR5cGUgaXMgc2V0IGFzIENvbnRyb2wtU3RyZXNzLiBXZSB0aGVyZWZvcmUgbmVlZCB0byByZXZlcnNlIHRoZSBzaWducyBvZiB0aGUgZml4ZWQgZWZmZWN0cyBpbiBvcmRlciB0byBhY3R1YWxseSBnZXQgdGhlIHJlc3VsdHMgd2Ugd2FudCAoU3RyZXNzLUNvbnRyb2wpLgoKPGJyPgoKCiMjIyMgU3ViamVjdGl2ZSBTdHJlc3Mgey0gLnRhYnNldH0KCiMjIyMjIE1vZGVsIHstfQpgYGB7cn0KY29udHJhc3RzKGRmX0VNQSRXZWVrX1R5cGUpIDwtIGNvbnRyLnRyZWF0bWVudChjKCJDb250cm9sIiwgIlN0cmVzcyIpKQptb2RlbC5zdHJlc3NCSU5fd2VlayA8LSBnbG1lcihzc190b3RfYmluIH4gV2Vla19UeXBlICsgKDErV2Vla19UeXBlfGNhc3Rvcl9yZWNvcmRfaWQpLCBjb250cmFzdHM9bGlzdChXZWVrX1R5cGU9ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX0VNQSwgZmFtaWx5PWJpbm9taWFsKCksIGNvbnRyb2w9Z2xtZXJDb250cm9sKGNhbGMuZGVyaXZzPUZBTFNFKSkKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVsLnN0cmVzc0JJTl93ZWVrLCBzaG93LnN0YXQ9VFJVRSwgc2hvdy5zZT1UUlVFKSRrbml0cikKYGBgCgo8YnI+CgojIyMjIyBQbG90IHstfQpgYGB7cn0KCmRmX0VNQS5zc19zdW0gPC0gZGZfRU1BICU+JSBkcGx5cjo6Z3JvdXBfYnkoY2FzdG9yX3JlY29yZF9pZCwgd2Vla190eXBlLCBzc190b3RfYmluKSAlPiUgZmlsdGVyKHNzX3RvdF9iaW49PSJTdHJlc3MiKSAlPiUgZHBseXI6OnN1bW1hcmlzZShzc190b3RfYmluPWxlbmd0aChzc190b3RfYmluKSkKCnBsb3Quc3RyZXNzX3dlZWsgPC0gZ2dwbG90KGRmX0VNQS5zc19zdW0sIGFlcyh4PXdlZWtfdHlwZSwgeT1zc190b3RfYmluLCBjb2xvcj1jYXN0b3JfcmVjb3JkX2lkKSkgKyAKICAgICAgICAgICBnZW9tX2xpbmUoYWxwaGE9MC4xNSwgc3RhdD0ic3VtbWFyeSIpICsgCiAgICAgICAgICAgIGdlb21fc21vb3RoKGFlcyhjb2xvcj1OQSksIG1ldGhvZD0ibG0iLCBhbHBoYT0xLCBzaXplPTEsIHNlPUYpKwogICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygwLDEpLGxhYmVscyA9IGMoIkNvbnRyb2xcbldlZWsiLCJTdHJlc3NcbldlZWsiKSkrCiAgICAgICAgICAgeWxhYigiTnVtYmVyIG9mIGJlZXBzIHdpdGggc3RyZXNzIikgKwogICAgICAgICAgIGdndGhlbWUyICsKICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEwLCBjb2xvdXI9ImJsYWNrIiksCiAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTEwKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9OCwgY29sb3VyPSJibGFjayIgKSkKcGxvdC5zdHJlc3Nfd2VlawpgYGAKCjxicj4KCiMjIyMgUG9zaXRpdmUgQWZmZWN0IHstIC50YWJzZXR9CgojIyMjIyBNb2RlbCB7LX0KYGBge3J9Cm1vZGVsLnBvc193ZWVrIDwtIGxtZXIobW9vZF9wb3NpdGl2ZV9jcyB+IFdlZWtfVHlwZSArICgxICsgV2Vla19UeXBlfGNhc3Rvcl9yZWNvcmRfaWQpLAogICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfRU1BLCAKICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sPWxtZXJDb250cm9sKGNhbGMuZGVyaXZzID1GKSwKICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChXZWVrX1R5cGU9Y29udHIudHJlYXRtZW50KDIpKSApCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtb2RlbC5wb3Nfd2Vlaywgc2hvdy5zdGF0PVRSVUUsIHNob3cuc2U9VFJVRSkka25pdHIpCmBgYAoKIyMjIyMgUGxvdCB7LX0KYGBge3J9CnBsb3QucGFfd2VlayA8LSBnZ3Bsb3QoZGZfRU1BLCBhZXMoeD13ZWVrX3R5cGUsIHk9bW9vZF9wb3NpdGl2ZV9jcywgY29sb3I9Y2FzdG9yX3JlY29yZF9pZCkpICsgCiAgICAgICAgICAgIGdlb21fbGluZShhbHBoYT0wLjE1LCBzdGF0PSJzdW1tYXJ5IikgKyAKICAgICAgICAgICBnZW9tX3Ntb290aChhZXMoY29sb3I9TkEpLCBtZXRob2Q9ImxtIiwgYWxwaGE9MSwgc2l6ZT0xLCBzZT1GKSsKICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwxKSxsYWJlbHMgPSBjKCJDb250cm9sXG5XZWVrIiwiU3RyZXNzXG5XZWVrIikpKwogICAgICAgICAgIHlsYWIoIkF2ZXJhZ2UgcG9zaXRpdmUgYWZmZWN0IChhLnUuKSIpICsKICAgICAgICAgICBnZ3RoZW1lMiArCiAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMCwgY29sb3VyPSJibGFjayIpLAogICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZT0xMCksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTgsIGNvbG91cj0iYmxhY2siICkpCnBsb3QucGFfd2VlawpgYGAKCgojIyMgUmVpc2R1YWwgUmVzaWxpZW5jZSBTY29yZSB7LSAudGFic2V0fQpXZSBub3cgZXh0cmFjdCB0aGUgZml4ZWQgYW5kIHJhbmRvbSBlZmZlY3RzIG9mIGVhY2ggb2Ygb3VyIG1vZGVscywgc28gdGhhdCB3ZSBjYW4gdXNlIHRoZW0gaW4gYSBzaW5nbGUgbGluZWFyIG1vZGVsLiBXZSBmaXJzdCBkbyB0aGlzIGZvciBTUywgYW5kIHRoZW4gUEEuIEZpbmFsbHkgd2UgY29tYmluZSB0aGVtIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZSB0aGF0IHdlIGNhbiB1c2UgZm9yIHRoZSBhbmFseXNpcy4gV2UgZG8gdGhpcyBieSBleHRyYWN0aW5nIHRoZSBmaXhlZCBlZmZlY3RzIGVzdGltYXRlcyBmcm9tIHRoZSBtYWluIG1vZGVscyBvZiBzdWJqZWN0aXZlIHN0cmVzcyBhbmQgcG9zaXRpdmUgYWZmZWN0IGZvciB0aGUgcmFuZG9tIGVmZmVjdCBvZiBzdWJqZWN0LgpgYGB7cn0KIyBTdWJqZWN0aXZlIHN0cmVzcwpmaXhlZF9zdHJlc3MyIDwtIGNvZWYobW9kZWwuc3RyZXNzQklOX3dlZWspJGNhc3Rvcl9yZWNvcmRfaWQKZml4ZWRfc3RyZXNzMiRpZCA8LSByb3duYW1lcyhmaXhlZF9zdHJlc3MyKQpyYW5kb21fc3RyZXNzMiA8LSByYW5lZihtb2RlbC5zdHJlc3NCSU5fd2VlaykkY2FzdG9yX3JlY29yZF9pZAojIFBvc2l0aXZlIGFmZmVjdApmaXhlZF9wb3MgPC0gKGNvZWYobW9kZWwucG9zX3dlZWspJGNhc3Rvcl9yZWNvcmRfaWQpCmZpeGVkX3BvcyRpZCA8LSByb3duYW1lcyhmaXhlZF9wb3MpCnJhbmRvbV9wb3MgPC0gcmFuZWYobW9kZWwucG9zX3dlZWspJGNhc3Rvcl9yZWNvcmRfaWQKCmBgYAoKV2UgZmluYWxseSBjb21iaW5lIHRoZW0gaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lIHRoYXQgd2Ugd2lsbCB1c2UgaW4gdGhlIHNlY29uZGFyeSBtb2RlbApgYGB7cn0KZGZfc3RyZXNzcnggPC0gbWVyZ2UoZml4ZWRfc3RyZXNzMiwgZml4ZWRfcG9zLCBieT0iaWQiLCBzdWZmaXhlcz1jKCJfc3RyZXNzIiwiX3BhIikpCm5hbWVzKGRmX3N0cmVzc3J4KSA8LSBjKCJpZCIsInN0cmVzc19pbnQiLCJzdHJlc3NfZmUiLCAgInBhX2ZlIiwgInBhX2ludCIsICJwYV9tZWFuIikKYGBgCgojIyMjIE1vZGVsIHstfQpXZSBub3cgZ28gdG8gb3VyIHNlY29uZCBsZXZlbCBtb2RlbHMuIEhlcmUsIHdlIG1vZGVsIHRoZSBlZmZlY3Qgb2YgY2hhbmdlcyBpbiBzdWJqZWN0aXZlIHN0cmVzcyByZXBvcnRzIG9uIGNoYW5nZXMgaW4gbW9vZCBiZXR3ZWVuIHRoZSB0d28gd2Vla3MuIFdlIHNlZSBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB0d28uIFRoZSBtb3JlIHN0cmVzcyB5b3UgZXhwZXJpZW5jZSwgdGhlIGxvd2VyIHlvdXIgcG9zaXRpdmUgYWZmZWN0IGdldHMgcmVsYXRpdmUgdG8gYmFzZWxpbmUuICBXZSBleHRyYWN0IGZyb20gdGhlIG1vZGVsIG9mIGNoYW5nZSBpbiBhZmZlY3QgYXMgYSBmdW5jdGlvbiBvZiBjaGFuZ2UgaW4gc3ViamVjdGl2ZSBzdHJlc3MgcmVwb3J0cyB0aGUgZml0dGVkIHZhbHVlcywgcmVzaWR1YWxzLCBwcmVkaWN0ZWQgdmFsdWUsIGFuZCBwbG90IHRoZW0uIEZyb20gdGhlIHJlc2lkdWFscywgd2Ugc2VlIHRoYXQgdGhvc2UgYWJvdmUgdGhlIGxpbmUgYXJlIHBlb3BsZSB3aG8gZXhwZXJpZW5jZSBsZXNzIGNoYW5nZSBpbiBhZmZlY3QgaW4gcmVzcG9uc2UgdG8gc3RyZXNzLCBhbmQgdGhvc2UgYmVsb3cgZXhwZXJpZW5jZSBtb3JlIHJlZHVjdGlvbnMgaW4gcG9zaXRpdmUgYWZmZWN0IGluIHJlc3BvbnNlIHRvIHN0cmVzcy4gU28gdGhvc2Ugd2l0aCBuZWdhdGl2ZSByZXNpZHVhbHMgd291bGQgYmUgc3RyZXNzIHNlbnNpdGl2ZSwgYW5kIHRob3NlIHdpdGhvdXQgd291bGQgYmUgcmVzaWxpZW50LiAKYGBge3J9Cm1vZGVsLnJlc2lkdWFsX3JlZ3Jlc3NvcnNCSU4gPC0gbG0ocGFfZmUgfiBzdHJlc3NfZmUsIGRhdGE9ZGZfc3RyZXNzcngpCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtb2RlbC5yZXNpZHVhbF9yZWdyZXNzb3JzQklOLCBzaG93LnN0YXQ9VFJVRSwgc2hvdy5zZT1UUlVFKSRrbml0cikKCiMgQmluYXJpemVkIE1vZGVsCmRmX3N0cmVzc3J4JGZpdHNCSU4gPC0gbW9kZWwucmVzaWR1YWxfcmVncmVzc29yc0JJTiRmaXR0ZWQudmFsdWVzCmRmX3N0cmVzc3J4JHJlc0JJTiA8LSBtb2RlbC5yZXNpZHVhbF9yZWdyZXNzb3JzQklOJHJlcwpkZl9zdHJlc3NyeCRlZmZCSU4gPC1tb2RlbC5yZXNpZHVhbF9yZWdyZXNzb3JzQklOJGVmZmVjdHMKZGZfc3RyZXNzcngkcHJlZEJJTiA8LSBwcmVkaWN0KG1vZGVsLnJlc2lkdWFsX3JlZ3Jlc3NvcnNCSU4pCmBgYAoKCiMjIyMgUGxvdCB7LX0KYGBge3J9CnBsb3QucmVzaWR1YWwgPC0gZ2dwbG90KGRmX3N0cmVzc3J4LCBhZXMoeD1zdHJlc3NfZmUsIHk9cGFfZmUpKSArIAogICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIHNlPUYsIGNvbG91cj0iZ3JleSIpKyAgICAgICAgICAgICAgICAgICAgICAgICAgIyBQbG90IGxpbmVhciByZWxhdGlvbnNoaXAKICAgIGdlb21fcG9pbnQoYWVzKHk9Zml0c0JJTiksIHNoYXBlPTEsIHNpemU9MC4yKSsgICAgICAgICAgICAgICAgICAgICAgICAgICMgRml0cyBkb3RzIG9uIHRoZSBsaW5lCiAgICBnZW9tX3NlZ21lbnQoYWVzKHhlbmQ9c3RyZXNzX2ZlLCB5ZW5kID0gZml0c0JJTiksIGFscGhhID0gLjIpICsgICAgICAjIEZpdHMgdGhlIGxpbmVzIGJldHdlZW0gdGhlIGZpdHRlZCB2YWx1ZXMgb24gdGhlIGxpbmUsIGFuZCByZXNpZHVhbHMKICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPXJlc0JJTikpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgRHJhdyByZXNpZHVhbCBkb3RzICsgY29sb3VyIHRoZW0KICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAicmVkIiwgbWlkID0gImdob3N0d2hpdGUiLCBoaWdoID0gImJsdWUiKSsgICMgU2NhbGUgdGhlIGNvbG91cgogICAgeGxhYigiRkUgU3RyZXNzIikgKyB5bGFiKCJGRSBQb3NpdGl2ZSBBZmZlY3QiKSArCiAgICBnZ3RoZW1lMiArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksYXhpcy5saW5lLng9KQpwbG90LnJlc2lkdWFsCmBgYAoKIyMjIEZ1bGwgUGxvdCB7LX0KYGBge3J9CmdnYXJyYW5nZSgKICAgICAgICAgIGdnYXJyYW5nZShOVUxMLHBsb3Quc3RyZXNzX3dlZWssICBOVUxMLCBwbG90LnBhX3dlZWssIG5jb2w9MiwgbnJvdz0yLCB3aWR0aHM9YygwLjA1LDEsMSksIGxhYmVscz1jKCJBIiwiIiwgIkIiKSksIAogICAgICAgICAgTlVMTCwgCiAgICAgICAgICBwbG90LnJlc2lkdWFsLCB3aWR0aHM9YygxLDAuMDUsMS4yKSwgCiAgICAgICAgICBuY29sPTMsIGxhYmVscz1jKCIiLCJDIiwgIiIpKTsgZ2dzYXZlKCJmaWd1cmVzL0ZpZ3VyZV8yX0VNQS5zdmciLCBkZXZpY2U9InN2ZyIsIGRwaT0zMDAsIGJnPSJ3aGl0ZSIpCmBgYAoKIyMjIENvcnJlbGF0aW9uIHdpdGggUHN5Y2ggey19CkZpbmFsbHkgd2UgY2hlY2sgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gb3VyIHN1YmplY3RpdmUgc3RyZXNzIG1lYXN1cmUsIGFuZCBvdXIgcGVyc29uYWxpdHkgdHJhaXRzLiBUaGlzIGFsbG93cyB1cyB0byB2YWxpZGF0ZSB0aGF0IG91ciBzdHJlc3MgcmVzaWxpZW5jZSBzY29yZSBpcyByZWxhdGVkIHRvIHByZXZpb3VzbHkgbGlua2VkIHNjb3JlcyBmcm9tIHRoZSBsaXRlcmF0dXJlLiBUbyBkbyB0aGlzLCB3ZSBtZXJnZSB0aGUgcHN5Y2ggZGF0YSBmcmFtZSBjb250YWluaW5nIHRoZSBxdWVzdGlvbm5haXJlcyB0aGF0IHBhcnRpY2lwYW50cyBmaWxsZWQgaW4sIHdpdGggdGhlIHJlc2lkdWFsIGRhdGEgZnJhbWUsIGFuZCBkbyBzb21lIG1hZ2ljIHRvIHB1dCBhbGwgdGhlIGRhdGEgdG9nZXRoZXIuIFdlIHRoZW4gcGxvdCBhIGNvcnJlbGF0aW9uIG1hdHJpeC4gT3VyIHNjb3JlcyBhcmUgbGlua2VkIHRvIG5ldXJvdGljaXNtLCB3aGljaCBpcyBncmVhdCEgCmBgYHtyfQpkZl9wc3ljaC5zdWIgPC0gZGZfcHN5Y2ggJT4lIGRwbHlyOjpyZW5hbWUoaWQ9c3ViX2lkKSAlPiUgZHBseXI6OnNlbGVjdChpZCwgKCJuZW9fbyIpLCBjb250YWlucygibmVvX2MiKSwgY29udGFpbnMoIm5lb19lIiksIGNvbnRhaW5zKCJuZW9fYSIpLCBjb250YWlucygibmVvX24iKSwgY29udGFpbnMoImJkaV90b3RhbCIpLCAidHJhaXRfdG90YWwiKQpkZl9zdHJlc3Muc3ViIDwtIGRmX3N0cmVzc3J4ICU+JSBkcGx5cjo6c2VsZWN0KGlkLCBjb250YWlucygiZmUiKSwgc3RhcnRzX3dpdGgoInJlcyIpICkKZGZfc3RyZXNzLnBzeWNoIDwtIG1lcmdlKGRmX3N0cmVzcy5zdWIsIGRmX3BzeWNoLnN1YiwgYnk9ImlkIiklPiUgcmV0eXBlKCkKbmFtZXMoZGZfc3RyZXNzLnBzeWNoKSA8LWMoImlkIiwgIlBBIiwgIlNTX0JJTiIsICJSZXNfQklOIiwgIk5FT19PIiwgIk5FT19DIiwgIk5FT19FIiwgIk5FT19BIiwgIk5FT19OIiwgIkJESSIsICJTVEFJX1QiKQpkZl9zdHJlc3MucHN5Y2guY29yIDwtIGRmX3N0cmVzcy5wc3ljaFtjKDI6MTEpXQpkZl9zdHJlc3MucHN5Y2guY29yIDwtIGRhdGEuZnJhbWUobGFwcGx5KGRmX3N0cmVzcy5wc3ljaC5jb3IsIGZ1bmN0aW9uKHgpIHNjYWxlKHgsIGNlbnRlciA9IFRSVUUsIHNjYWxlPVQpKSkKYGBgCgpgYGB7cn0KY29ybWF0LnN0ciA8LSByY29ycihhcy5tYXRyaXgoZGZfc3RyZXNzLnBzeWNoLmNvcikpCmNvcnJwbG90KGNvcm1hdC5zdHIkciwgbWV0aG9kPSJudW1iZXIiLCBwLm1hdD1jb3JtYXQuc3RyJFAsIHR5cGU9Imxvd2VyIiwgZGlhZz1GQUxTRSwgaW5zaWc9InBjaCIsIGNsLnBvcz0ibiIpCmBgYApgYGB7cn0KYXNpc19vdXRwdXQodGFiX21vZGVsKGxtKFJlc19CSU4gfiAxICsgTkVPX04sIGRhdGE9ZGZfc3RyZXNzLnBzeWNoICkpJGtuaXRyKQpnZ3Bsb3QoZGZfc3RyZXNzLnBzeWNoLCBhZXMoeT1ORU9fTiwgeD1SZXNfQklOKSkgKyBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKyBnZ3RoZW1lMgpgYGAKCgoKIyBMYWJvcmF0b3J5IFN0cmVzcyBJbmR1Y3Rpb24KQmVmb3JlIHdlIGRvIGFueSBhbmFseXNpcyByZWdhcmRpbmcgdGhlIGVmZmVjdHMgb2Ygc3RyZXNzIG9uIHRoZSBicmFpbiBhbmQgb3VyIHRhc2tzLCB3ZSBuZWVkIHRvIHZhbGlkYXRlIG91ciBzdHJlc3MgaW5kdWN0aW9uIHByb2NlZHVyZS4gU2luY2UgdGhpcyBpcyBhIHdpdGhpbiBzdWJqZWN0IGRlc2lnbiwgYWxsIHBhcnRpY2lwYW50cyB1bmRlcndlbnQgYm90aCB0aGUgc3RyZXNzIGluZHVjdGlvbiBwcm9jZWR1cmUsIGFuZCBhIG1hdGNoZWQgY29udHJvbCBwcm9jZWR1cmUuIFRoZSBzdHJlc3MgcHJvY2VkdXJlIGludm9sdmVkIGEgbm92ZWwgZXhwZXJpbWVudGVyIHBsYWNpbmcgdGhlIHBhcnRpY2lwYW50cyBmb290IGluIGljZSB3YXRlciBvZiAzIG1pbnV0ZXMsIGZvbGxvd2VkIGJ5IGEgZGlmZmljdWx0IG1lbnRhbCBhcml0aG1ldGljIHRhc2sgZm9yIGFub3RoZXIgMyBtaW51dGVzLiBUaGUgY29udHJvbCBwcm9jZWR1cmUgd2FzIHBlcmZvcm1lZCBieSBhIGZhbWlsaWFyIGV4cGVyaW1lbnRlciwgd2l0aCByb29tIHRlbXBlcmF0dXJlIHdhdGVyLCBhbmQgYW4gZWFzeSBhcml0aG1ldGljIHRhc2suIFRvIHZhbGlkYXRlIHRoZSBwcm9jZWR1cmUsIHdlIGZpcnN0IGFuYWx5emUgb3VyIGNvbGxlY3RlZCBwaHlzaW9sb2d5IGRhdGEgd2hpY2ggaW5jbHVkZXMgc2FsaXZhIGFuZCBoZWFydCByYXRlIG1lYXN1cmVzLiBXZSBhbHNvIGNvbGxlY3Qgc2tpbiBjb25kdWN0YW5jZSBkYXRhLCBidXQgdGhhdCBzdGlsbCBuZWVkcyB0byBiZSBkb25lLCBhbmQgaXMgb3V0c2lkZSB0aGUgc2NvcGUgb2YgdGhlIGN1cnJlbnQgcGFwZXIuIAoKIyMgRGF0YQpUaGUgc2FsaXZhIG1lYXN1cmVzIGFyZSBkZXJpdmVkIGZyb20gc2FtcGxlcyBjb2xsZWN0ZWQgZHVyaW5nIHRoZSBzY2FubmluZyBhdCAwIG1pbiwgNiBtaW4sIDMwIG1pbiwgNTAgbWluLCBhbmQgMTIwIG1pbiAoYXBwcm94aW1hdGVseSkgZnJvbSBzdHJlc3MgaW5kdWN0aW9uL2NvbnRyb2wgcHJvY2VkdXJlLiBBZGRpdGlvbmFsIHNhbXBsZXMgYXJlIGNvbGxlY3RlZCBpbiB0aGUgc3RyZXNzL2NvbnRyb2wgd2Vla3MgYXQgaG9tZS4gVGhlc2Ugc2FtcGxlcyBhcmUgYW5hbHlzZWQgb2Zmc2l0ZSBhbmQgcmV0dXJuZWQgaW4gYW4gZXhjZWwgc2hlZXQsIHdpdGggdGhlIHRpbWluZyBsb2dzIGJlaW5nIHJlY29yZGVkIGluIENhc3RvciBkdXJpbmcgdGhlIHNjYW5uaW5nLiBUaGUgaGVhcnQgcmF0ZSBtZWFzdXJlcyBhcmUgYWxzbyBjb2xsZWN0ZWQgZHVyaW5nIHRoaXMgdGltZSB2aWEgQnJhaW5hbXAgd2l0aCBhIHB1bHNlIG94eW1ldGVyLiBUaGVzZSBtZWFzdXJlcyB3ZXJlIGNsZWFuZWQgaW4gbWF0bGFiIHVzaW5nIFtIZVJhXShodHRwczovL2dpdGh1Yi5jb20vY2FuLWxhYi9oZXJhKSwgYW5kIHRoZW4gY29tcGlsZWQgdXNpbmcgYSBjdXN0b20gc2NyaXB0LiBXZSBmaXJzdCBkbyBzb21lIHNpbXBsZSBjbGVhbmluZyBwcm9jZWR1cmVzIHRvIG1ha2UgYW5hbHlzaXMgZWFzaWVyIGZvciBlYWNoIG9mIHRoZSBtZWFzdXJlcy4gCgojIyMgU2FsaXZhIHstfQpTYWxpdmFyeSBjb3J0aXNvbCBhbmQgYW15bGFzZSBpcyBjb2xsZWN0ZWQgc2V2ZXJhbCB0aW1lcyBpbiBvdXIgc3R1ZHkuIFR3aWNlIGR1cmluZyBhbiBleGFtIHdlZWssIGFuZCBhIGNvbnRyb2wgd2VlayAobm9uLWV4YW0pLCBpbiBhZGRpdGlvbiB0byB0aGUgNSBzYWxpdmEgc2FtcGxlcyBkdXJpbmcgZWFjaCBvZiB0aGUgTVJJIHNlc3Npb25zIChzdHJlc3MgYW5kIGNvbnRyb2wpLiBBIHNwcmVhZHNoZWV0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgc2FsaXZhIGFzc2F5cyB3YXMgc2VudCBmcm9tIHRoZSBvZmZzaXRlIGFuYWx5c2lzIHNpdGUuIFdlIGFsc28gcmVjb3JkIGxvZ3MgZm9yIHRoZSB0aW1lIGF0IHdoaWNoIGVhY2ggc2FtcGxlIHdhcyBhY3F1aXJlZC4gU2luY2UgdGhpcyBpcyBvdXIgbWFpbiBzdHJlc3MgdmFsaWRhdGlvbiBtZWFzdXJlLCB3ZSBuZWVkIHRvIG1ha2Ugc3VyZSB0byBnZXQgdGhlIGZpbGVzIGNsZWFuIGZpcnN0LiBXZSB0aGVyZWZvcmUgaW1wb3J0IHRoZSBsb2dzIGNvbnRhaW5pbmcgdGltaW5nIGluZm9ybWF0aW9uIGZvciBvdXIgc2FtcGxlcyB0byBwcmVwcm9jZXNzIHRoZW0gYW5kIGFkZCB0aGVtIHRvIHRoZSByZXN1bHRzIGZyb20gdGhlIHNhbGl2YSBhc3NheXMuIEEgZmV3IHRoaW5ncyBhcmUgZG9uZSBoZXJlLCBpbmNsdWRpbmcgc3Vic2V0dGluZyB0aGUgZGF0YSBmcmFtZXMsIGFuZCBjYWxjdWxhdGluZyB0aGUgcmVsYXRpdmUgdGltZSBvZiBlYWNoIHNhbXBsZXMgdXNpbmcgdGhlIGZpcnN0IHNhbXBsZSBhcyB0aGUgc3RhcnRpbmcgdGltZS4gV2UgY2FuIHRoZW4gaW1wb3J0IHRoZSBhY3R1YWwgcmVzdWx0cyBmcm9tIHRoZSBzYWxpdmFyeSBhc3NheXMuIE9uZSBwYXJ0aWNpcGFudCBoYWQgYW4gaW5jb3JyZWN0IHRpbWUgc3RhbXAsIHNvIHdlIGFsc28gY29ycmVjdCBpdCBoZXJlIChpdCBoYWQgdGhlIHdyb25nIGhvdXIgdmFsdWUpLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBHZXQgY2FzdG9yIGRmCmRmX2Nhc3RvciA8LSByZWFkX2V4Y2VsKCJkYXRhL2Nhc3Rvcl9kYXRhX2V4cG9ydC54bHN4IixzaGVldCA9ICJTdHVkeSByZXN1bHRzIikKCiMgR2V0IGRlbW9ncmFwaGljcyBERgpkZl9kZW1vZ3JhcGhpY3MgPC0gcmVhZF9kZWxpbSgiZGF0YS9kZW1vX2Fub24uY3N2IiwgZGVsaW09Ilx0IikgJT4lIGNsZWFuX25hbWVzKCkgJT4lIGRwbHlyOjpyZW5hbWUoc3ViamVjdF9udW1iZXI9InN1YmplY3RfaWQiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShjb250cmFjZXB0aXZlX3VzZSkpICU+JSAKICBkcGx5cjo6bXV0YXRlKHNleD1pZmVsc2UoY29udHJhY2VwdGl2ZV91c2U9PSJNYWxlIiwgIk1hbGUiLCAiRmVtYWxlIiksCiAgICAgICAgICAgICAgICBjb250cmFjZXB0aXZlX3VzZT1pZmVsc2UoY29udHJhY2VwdGl2ZV91c2U9PSJjIiwgTkEsIGNvbnRyYWNlcHRpdmVfdXNlKSkgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAojIENsZWFuIFN1YmplY3QgbnVtYmVycwpkZl9jYXN0b3IgPC0gZGZfY2FzdG9yICU+JSBzZXBhcmF0ZSgiUmVjb3JkIElkIiwgYygic3ViamVjdF9udW1iZXIiLCAiZGJsX3Nlc3MiKSwgIl9zIikKZGZfY2FzdG9yJGRibF9zZXNzW2lzLm5hKGRmX2Nhc3RvciRkYmxfc2VzcyldICA8LSAxCmRmX2Nhc3RvciA8LSBzdWJzZXQoZGZfY2FzdG9yLCBkZl9jYXN0b3IkZGJsX3Nlc3MgIT0gMikgCgojIFN1YnNldCBkZgpkZl9jYXN0b3IgPC0gc3Vic2V0KGRmX2Nhc3Rvciwgc2VsZWN0PWMoInN1YmplY3RfbnVtYmVyIiwgIm1yaV9kYXRhX2NvbnRyb2wiLCAibXJpX2RhdGFfY29udHJvbF8xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29ydF8xIiwgImNvcnRfMiIsICJjb3J0XzMiLCAiY29ydF80IiwgImNvcnRfNSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29ydF8xXzEiLCAiY29ydF8yXzEiLCAiY29ydF8zXzEiLCAiY29ydF80XzEiLCAiY29ydF81XzEiKSkKZGZfY2FzdG9yW2RmX2Nhc3RvciA8IDBdIDwtIE5BCmRmX2Nhc3RvciA8LSBkZl9jYXN0b3JbZGZfY2FzdG9yJG1yaV9kYXRhX2NvbnRyb2whPSIwMS0wMS0yOTk5IixdIApkZl9jYXN0b3IgPC0gdW5pcXVlKGRmX2Nhc3RvcikKCiMgRm9ybWF0IGRhdGVzCmRmX2Nhc3RvciRtcmlfZGF0ZV9jb250cm9sIDwtIGFzLkRhdGUoZGZfY2FzdG9yJG1yaV9kYXRhX2NvbnRyb2wsIGZvcm1hdD0iJWQtJW0tJVkiKQpkZl9jYXN0b3IkbXJpX2RhdGVfc3RyZXNzIDwtIGFzLkRhdGUoZGZfY2FzdG9yJG1yaV9kYXRhX2NvbnRyb2xfMSwgZm9ybWF0PSIlZC0lbS0lWSIpCgojIENhbGN1bGF0ZSB3aGljaCBpcyBmaXJzdCBzY2FuCmRmX2Nhc3RvciRmaXJzdF9zY2FuX2RpZmYgPC0gTlVMTApkZl9jYXN0b3IkZmlyc3Rfc2Nhbl9kaWZmIDwtIGRmX2Nhc3RvciRtcmlfZGF0ZV9jb250cm9sIC0gZGZfY2FzdG9yJG1yaV9kYXRlX3N0cmVzcwpkZl9jYXN0b3IkZmlyc3Rfc2Nhbl9kaWZmIDwtIGFzLm51bWVyaWMoZGZfY2FzdG9yJGZpcnN0X3NjYW5fZGlmZiwgdW5pdHM9ImRheXMiKQoKIyBEZXBlZG5kaW5nIG9uIGRpZmZlcmVuY2UgYmV0d2VlbSBkYXRlcywgc2V0IGZpcnN0IHNjYW4KZGZfY2FzdG9yJGZpcnN0X3NjYW4gPC0gIkNvbnRyb2wiCmRmX2Nhc3RvciRmaXJzdF9zY2FuW2RmX2Nhc3RvciRmaXJzdF9zY2FuX2RpZmYgPiAwXSA8LSAiU3RyZXNzIgoKIyBDYWxjdWFsdGUgdGltZSBmcm9tIGZpcnN0IHNhbXBsZQpkZl9jYXN0b3IkdF8xX2MgPC0gYXMubnVtZXJpYyhkaWZmdGltZShhcy5JVGltZShkZl9jYXN0b3IkY29ydF8xKSwgYXMuSVRpbWUoZGZfY2FzdG9yJGNvcnRfMSksIHVuaXRzPSdtaW4nKSkKZGZfY2FzdG9yJHRfMl9jIDwtIGFzLm51bWVyaWMoZGlmZnRpbWUoYXMuSVRpbWUoZGZfY2FzdG9yJGNvcnRfMiksIGFzLklUaW1lKGRmX2Nhc3RvciRjb3J0XzEpLCB1bml0cz0nbWluJykpCmRmX2Nhc3RvciR0XzNfYyA8LSBhcy5udW1lcmljKGRpZmZ0aW1lKGFzLklUaW1lKGRmX2Nhc3RvciRjb3J0XzMpLCBhcy5JVGltZShkZl9jYXN0b3IkY29ydF8xKSwgdW5pdHM9J21pbicpKSAKZGZfY2FzdG9yJHRfNF9jIDwtIGFzLm51bWVyaWMoZGlmZnRpbWUoYXMuSVRpbWUoZGZfY2FzdG9yJGNvcnRfNCksIGFzLklUaW1lKGRmX2Nhc3RvciRjb3J0XzEpLCB1bml0cz0nbWluJykpIApkZl9jYXN0b3IkdF81X2MgPC0gYXMubnVtZXJpYyhkaWZmdGltZShhcy5JVGltZShkZl9jYXN0b3IkY29ydF81KSwgYXMuSVRpbWUoZGZfY2FzdG9yJGNvcnRfMSksIHVuaXRzPSdtaW4nKSkgCiMgU3RyZXNzIApkZl9jYXN0b3IkdF8xX3MgPC0gYXMubnVtZXJpYyhkaWZmdGltZShhcy5JVGltZShkZl9jYXN0b3IkY29ydF8xXzEpLCBhcy5JVGltZShkZl9jYXN0b3IkY29ydF8xXzEgKSwgdW5pdHM9J21pbicpKSAKZGZfY2FzdG9yJHRfMl9zIDwtIGFzLm51bWVyaWMoZGlmZnRpbWUoYXMuSVRpbWUoZGZfY2FzdG9yJGNvcnRfMl8xKSwgYXMuSVRpbWUoZGZfY2FzdG9yJGNvcnRfMV8xICksIHVuaXRzPSdtaW4nKSkgCmRmX2Nhc3RvciR0XzNfcyA8LSBhcy5udW1lcmljKGRpZmZ0aW1lKGFzLklUaW1lKGRmX2Nhc3RvciRjb3J0XzNfMSksIGFzLklUaW1lKGRmX2Nhc3RvciRjb3J0XzFfMSApLCB1bml0cz0nbWluJykpCmRmX2Nhc3RvciR0XzRfcyA8LSBhcy5udW1lcmljKGRpZmZ0aW1lKGFzLklUaW1lKGRmX2Nhc3RvciRjb3J0XzRfMSksIGFzLklUaW1lKGRmX2Nhc3RvciRjb3J0XzFfMSApLCB1bml0cz0nbWluJykpIApkZl9jYXN0b3IkdF81X3MgPC0gYXMubnVtZXJpYyhkaWZmdGltZShhcy5JVGltZShkZl9jYXN0b3IkY29ydF81XzEpLCBhcy5JVGltZShkZl9jYXN0b3IkY29ydF8xXzEgKSwgdW5pdHM9J21pbicpKSAKCiMgTWFrZSBsb25nCmRmX2Nhc3Rvci5sb25nIDwtIHBpdm90X2xvbmdlcihkZl9jYXN0b3IsIGNvbHM9dF8xX2M6dF81X3MsIG5hbWVzX3RvPWMoInNhbXBsZV9udW1iZXIiKSwgdmFsdWVzX3RvPSJ0aW1lIikKIyBSZW5hbWUgU2FtcGxlIE51bWJlcgojIyBDb250cm9sIFNhbXBsZXMKZGZfY2FzdG9yLmxvbmckc2FtcGxlX251bWJlcltkZl9jYXN0b3IubG9uZyRzYW1wbGVfbnVtYmVyPT0idF8xX2MiXSA8LSAiX0NNUl8xIgpkZl9jYXN0b3IubG9uZyRzYW1wbGVfbnVtYmVyW2RmX2Nhc3Rvci5sb25nJHNhbXBsZV9udW1iZXI9PSJ0XzJfYyJdIDwtICJfQ01SXzIiCmRmX2Nhc3Rvci5sb25nJHNhbXBsZV9udW1iZXJbZGZfY2FzdG9yLmxvbmckc2FtcGxlX251bWJlcj09InRfM19jIl0gPC0gIl9DTVJfMyIKZGZfY2FzdG9yLmxvbmckc2FtcGxlX251bWJlcltkZl9jYXN0b3IubG9uZyRzYW1wbGVfbnVtYmVyPT0idF80X2MiXSA8LSAiX0NNUl80IgpkZl9jYXN0b3IubG9uZyRzYW1wbGVfbnVtYmVyW2RmX2Nhc3Rvci5sb25nJHNhbXBsZV9udW1iZXI9PSJ0XzVfYyJdIDwtICJfQ01SXzUiCiMjIFN0cmVzcyBzYW1wbGVzCmRmX2Nhc3Rvci5sb25nJHNhbXBsZV9udW1iZXJbZGZfY2FzdG9yLmxvbmckc2FtcGxlX251bWJlcj09InRfMV9zIl0gPC0gIl9TTVJfMSIKZGZfY2FzdG9yLmxvbmckc2FtcGxlX251bWJlcltkZl9jYXN0b3IubG9uZyRzYW1wbGVfbnVtYmVyPT0idF8yX3MiXSA8LSAiX1NNUl8yIgpkZl9jYXN0b3IubG9uZyRzYW1wbGVfbnVtYmVyW2RmX2Nhc3Rvci5sb25nJHNhbXBsZV9udW1iZXI9PSJ0XzNfcyJdIDwtICJfU01SXzMiCmRmX2Nhc3Rvci5sb25nJHNhbXBsZV9udW1iZXJbZGZfY2FzdG9yLmxvbmckc2FtcGxlX251bWJlcj09InRfNF9zIl0gPC0gIl9TTVJfNCIKZGZfY2FzdG9yLmxvbmckc2FtcGxlX251bWJlcltkZl9jYXN0b3IubG9uZyRzYW1wbGVfbnVtYmVyPT0idF81X3MiXSA8LSAiX1NNUl81IgoKCgojIEdldCBzYWxpdmEgcmVzdWx0cyArIGNsZWFuIHVwCmRmX3NhbGl2YSA8LSByZWFkX2V4Y2VsICgiZGF0YS9CYUxMU19Db3J0aXNvbFNhbXBsZXNfTWFzdGVyLnhsc3giLCBzaGVldD0ibWFzdGVyc2hlZXQiKQpkZl9zYWxpdmEgPC0gZGZfc2FsaXZhICU+JSByZXR5cGUoKSAlPiUgY2xlYW5fbmFtZXMoKQpkZl9zYWxpdmEkc3ViamVjdF9udW1iZXIgPC0gdG9sb3dlcihkZl9zYWxpdmEkc3ViamVjdF9udW1iZXIpCmRmX3NhbGl2YSA8LSBtZXJnZShkZl9zYWxpdmEsIGRmX2RlbW9ncmFwaGljcywgYnk9InN1YmplY3RfbnVtYmVyIikKCiMgTWVyZ2Ugd2l0aCBjYXN0b3IgZGYKZGZfc2FsaXZhIDwtIG1lcmdlKGRmX3NhbGl2YSwgZGZfY2FzdG9yLmxvbmcsIGJ5PWMoInN1YmplY3RfbnVtYmVyIiwic2FtcGxlX251bWJlciIpLCBhbGw9VCkKZGZfc2FsaXZhIDwtIHJlbmFtZV8oZGZfc2FsaXZhLCAiZmlyc3Rfc2NhbiI9ImZpcnN0X3NjYW4ueSIpCiNWYXJpYWJsZSBmb3IgU2NhbiBUeXBlCmRmX3NhbGl2YSA8LSBkZl9zYWxpdmEgJT4lIGRwbHlyOjptdXRhdGUoc2Nhbl90eXBlPWlmZWxzZShzdHJfZGV0ZWN0KHNhbXBsZV9udW1iZXIsICJDTVIiKSwgIkNvbnRyb2wiLCBOQSksIHNjYW5fdHlwZT1pZmVsc2Uoc3RyX2RldGVjdChzYW1wbGVfbnVtYmVyLCAiU01SIiksICJTdHJlc3MiLCBzY2FuX3R5cGUpKQoKIyBDb3JyZWN0IHRoZSB3cm9uZyB0aW1lCmRmX3NhbGl2YSRjb3J0XzNfMVtkZl9zYWxpdmEkY29ydF8zXzE9PSIxMjoyNSIgJiBkZl9zYWxpdmEkc3ViamVjdF9udW1iZXI9PSJzdWJfMDIzIl0gPC0gIjEzOjI1IgpgYGAgCgoKV2UgbmV4dCBjYWxjdWxhdGUgdGhlIHJlc3BvbnNlcyBvZiBpbnRlcmVzdCBmcm9tIHRoZSBjb3J0aXNvbCBkYXRhLiBUaGVzZSB3aWxsIGJlIHNpbmdsZSB2YWx1ZXMgb2YgcmVzcG9uc2l2aXR5IHRoYXQgd2UgY2FuIHVzZSBpbiBmb2xsb3ctdXAgbW9kZWxzIGFuZCBpbmNsdWRlIHRoZSBBVUMgYW5kIEhlbmNrZW5zIHJlc3BvbnNlLiBGb3IgdGhlIEFVQ2cgYW5kIEFVQ2ksIHdlIGZvbGxvdyB0aGUgZm9ybXVsYSBkZXJpdmVkIGZyb20gW1BydWVzc25lciBldCBhbC4gKDIwMDMpXShodHRwczovL3d3dy5zY2llbmNlZGlyZWN0LmNvbS9zY2llbmNlL2FydGljbGUvcGlpL1MwMzA2NDUzMDAyMDAxMDg3P3ZpYSUzRGlodWIpLiBXZSB0aGVuIG1lYXN1cmUgdGhlIGRpZmZlcmVuY2VzIGluIGJvdGggdGhlIEFVQ2kgYW5kIHRoZSBBVUNnIGluIHRoZSBzdHJlc3MgYW5kIGNvbnRyb2wgc2Vzc2lvbnMuIEZvciB0aGUgSFBBIHJlc3BvbnNlIGZyb20gSGVuY2tlbnMgZXQgYWwuLCB3ZSBpbnN0ZWFkIGNhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gcGVhayBtZWFzdXJlcyBpbiBzYWxpdmFyeSBjb3J0aXNvbC4gVGhlIGV4cGVjdGVkIHBlYWsgaW4gb3VyIHN0dWR5IGlzIHNhbXBsZSAzLCBzbyB3ZSBsb29rIGF0IHRoZSBkaWZmZXJlbmNlIGluIHNhbXBsZSAzIGluIHRoZSBzdHJlc3MgdnMgY29udHJvbCBzZXNzaW9ucywgd2hpbGUgY29ycmVjdGluZyBmb3IgYmFzZWxpbmUgYWNxdWlyZWQgYXQgaG9tZS4gVGhpcyBiYXNlbGluZSBjb3JyZWN0aW9uIGlzIHN1cGVyaW9yIGJlY2F1c2UgaXQgaXMgaW5kZXBlbmRlbnQgb2Ygb3JkZXIgZWZmZWN0cywgYW5kIHNjYW5uZXIgYXBwcmVoZW5zaW9uLiAKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBNYWtlIGEgd2lkZSBkZgpkZl9zYWxpdmEud2lkZSA8LSBkZl9zYWxpdmEgJT4lIGRwbHlyOjpzZWxlY3Qoc3ViamVjdF9udW1iZXIsICBmaXJzdF9zY2FuLCBzYW1wbGVfbnVtYmVyLCBjb3J0aXNvbCwgYWxwaGFfYW15bGFzZSwgdGltZSkgJT4lIAogIHBpdm90X3dpZGVyKGlkX2NvbHM9YyhzdWJqZWN0X251bWJlciksIG5hbWVzX2Zyb209c2FtcGxlX251bWJlciwgdmFsdWVzX2Zyb209Yyhjb3J0aXNvbCwgYWxwaGFfYW15bGFzZSwgdGltZSksIG5hbWVzX3NlcD0iIiwgdmFsdWVzX2ZuPWxpc3QoY29ydGlzb2w9bWVhbiwgYWxwaGFfYW15bGFzZT1tZWFuLCB0aW1lPW1lYW4pKSAKCiMgR2V0IHRoZSBBVUNnIAojIyBBVUNnIENvbnRyb2wKZGZfc2FsaXZhLndpZGUkQVVDZ19jb250cm9sIDwtICgKICAgICgoKGRmX3NhbGl2YS53aWRlJGNvcnRpc29sX0NNUl8xK2RmX3NhbGl2YS53aWRlJGNvcnRpc29sX0NNUl8yKS8yKSooZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfMikpICsKKCgoZGZfc2FsaXZhLndpZGUkY29ydGlzb2xfQ01SXzIrZGZfc2FsaXZhLndpZGUkY29ydGlzb2xfQ01SXzMpLzIpKihkZl9zYWxpdmEud2lkZSR0aW1lX0NNUl8zLWRmX3NhbGl2YS53aWRlJHRpbWVfQ01SXzIpKSArCigoKGRmX3NhbGl2YS53aWRlJGNvcnRpc29sX0NNUl8zK2RmX3NhbGl2YS53aWRlJGNvcnRpc29sX0NNUl80KS8yKSooZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfNC1kZl9zYWxpdmEud2lkZSR0aW1lX0NNUl8zKSkKKQojIyBBVUNnIFN0cmVzcwpkZl9zYWxpdmEud2lkZSRBVUNnX3N0cmVzcyA8LSAoCiAgICAoKChkZl9zYWxpdmEud2lkZSRjb3J0aXNvbF9TTVJfMStkZl9zYWxpdmEud2lkZSRjb3J0aXNvbF9TTVJfMikvMikqKGRmX3NhbGl2YS53aWRlJHRpbWVfU01SXzIpKSArCigoKGRmX3NhbGl2YS53aWRlJGNvcnRpc29sX1NNUl8yK2RmX3NhbGl2YS53aWRlJGNvcnRpc29sX1NNUl8zKS8yKSooZGZfc2FsaXZhLndpZGUkdGltZV9TTVJfMy1kZl9zYWxpdmEud2lkZSR0aW1lX1NNUl8yKSkgKwooKChkZl9zYWxpdmEud2lkZSRjb3J0aXNvbF9TTVJfMytkZl9zYWxpdmEud2lkZSRjb3J0aXNvbF9TTVJfNCkvMikqKGRmX3NhbGl2YS53aWRlJHRpbWVfU01SXzQtZGZfc2FsaXZhLndpZGUkdGltZV9TTVJfMykpKQoKIyBOb3cgZ2V0IEFVQ2kKIyMgQVVDaSBDb250cm9sCmRmX3NhbGl2YS53aWRlJEFVQ2lfY29udHJvbCA8LSBkZl9zYWxpdmEud2lkZSRBVUNnX2NvbnRyb2wgLSAoZGZfc2FsaXZhLndpZGUkY29ydGlzb2xfQ01SXzEqICgoZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfMikrKGRmX3NhbGl2YS53aWRlJHRpbWVfQ01SXzMtZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfMikrKGRmX3NhbGl2YS53aWRlJHRpbWVfQ01SXzQtZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfMykpKSAKIyMgQVVDaSBTdHJlc3MKZGZfc2FsaXZhLndpZGUkQVVDaV9zdHJlc3MgPC0gZGZfc2FsaXZhLndpZGUkQVVDZ19zdHJlc3MgLSAoZGZfc2FsaXZhLndpZGUkY29ydGlzb2xfU01SXzEqICgoZGZfc2FsaXZhLndpZGUkdGltZV9TTVJfMikrKGRmX3NhbGl2YS53aWRlJHRpbWVfU01SXzMtZGZfc2FsaXZhLndpZGUkdGltZV9TTVJfMikrKGRmX3NhbGl2YS53aWRlJHRpbWVfU01SXzQtZGZfc2FsaXZhLndpZGUkdGltZV9TTVJfMykpKSAKCiMjIEFVQyBEaWZmZXJlbmNlcwpkZl9zYWxpdmEud2lkZSRBVUNnX2RpZmZlcmVuY2UgPC0gZGZfc2FsaXZhLndpZGUkQVVDZ19zdHJlc3MgLSBkZl9zYWxpdmEud2lkZSRBVUNnX2NvbnRyb2wKZGZfc2FsaXZhLndpZGUkQVVDaV9kaWZmZXJlbmNlIDwtIGRmX3NhbGl2YS53aWRlJEFVQ2lfc3RyZXNzIC0gZGZfc2FsaXZhLndpZGUkQVVDaV9jb250cm9sCgojIEhlbmNrZW5zCmRmX3NhbGl2YS53aWRlJEhQQV9hY3QgPC0gKGRmX3NhbGl2YS53aWRlJGNvcnRpc29sX1NNUl8zIC0gZGZfc2FsaXZhLndpZGUkY29ydGlzb2xfQ01SXzEpLyhyb3dNZWFucyhjYmluZChkZl9zYWxpdmEud2lkZSRjb3J0aXNvbF9DV18xLCBkZl9zYWxpdmEud2lkZSRjb3J0aXNvbF9DV18yLCBkZl9zYWxpdmEud2lkZSRjb3J0aXNvbF9TV18xLCBkZl9zYWxpdmEud2lkZSRjb3J0aXNvbF9TV18yKSwgbmEucm09VFJVRSkpCmBgYAoKSW4gb3JkZXIgdG8gcGxvdCB0aGUgcmVzdWx0cywgd2UgYWxzbyBkZXJpdmUgdGhlIG1lYW4gdGltZXMgYXQgd2hpY2ggdGhlIHNhbXBsZXMgd2UgYWNxdWlyZWQuIEZpbmFsbHkgd2UgY2FuIGFsc28gY2xlYW4gdXAgc29tZSBmYWN0b3JzIGFuZCBvdGhlciByZWxhdGVkIGl0ZW1zIGluIHRoZSBkYXRhIGZyYW1lIHRvIG1ha2UgYW5hbHlzaXMgZWFzaWVyLiBBbHNvIGZpbHRlciBvdXQgdGhlIG5vbi1zY2FuIHJlbGF0ZWQgc2FsaXZhIHNhbXBsZXMgYmVjYXVzZSB0aGVzZSBhcmUgbm90IHJlYWxseSBvZiBpbnRlcmVzdCBoZXJlLiAKYGBge3J9CiNUaW1lIFBvaW50cyBmb3IgU2NhbiBTYW1wbGVzCmRmX3NhbGl2YSR0aW1lX3BvaW50W2RmX3NhbGl2YSRzYW1wbGVfbnVtYmVyPT0iX0NNUl8xInxkZl9zYWxpdmEkc2FtcGxlX251bWJlcj09Il9TTVJfMSJdPC0gbWVhbigoZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfMStkZl9zYWxpdmEud2lkZSR0aW1lX1NNUl8xKS8yLCBuYS5ybT1UUlVFKQpkZl9zYWxpdmEkdGltZV9wb2ludFtkZl9zYWxpdmEkc2FtcGxlX251bWJlcj09Il9DTVJfMiJ8ZGZfc2FsaXZhJHNhbXBsZV9udW1iZXI9PSJfU01SXzIiXTwtbWVhbigoZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfMitkZl9zYWxpdmEud2lkZSR0aW1lX1NNUl8yKS8yLCBuYS5ybT1UUlVFKQpkZl9zYWxpdmEkdGltZV9wb2ludFtkZl9zYWxpdmEkc2FtcGxlX251bWJlcj09Il9DTVJfMyJ8ZGZfc2FsaXZhJHNhbXBsZV9udW1iZXI9PSJfU01SXzMiXTwtbWVhbigoZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfMytkZl9zYWxpdmEud2lkZSR0aW1lX1NNUl8zKS8yLCBuYS5ybT1UUlVFKQpkZl9zYWxpdmEkdGltZV9wb2ludFtkZl9zYWxpdmEkc2FtcGxlX251bWJlcj09Il9DTVJfNCJ8ZGZfc2FsaXZhJHNhbXBsZV9udW1iZXI9PSJfU01SXzQiXTwtbWVhbigoZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfNCtkZl9zYWxpdmEud2lkZSR0aW1lX1NNUl80KS8yLCBuYS5ybT1UUlVFKQpkZl9zYWxpdmEkdGltZV9wb2ludFtkZl9zYWxpdmEkc2FtcGxlX251bWJlcj09Il9DTVJfNSJ8ZGZfc2FsaXZhJHNhbXBsZV9udW1iZXI9PSJfU01SXzUiXTwtbWVhbigoZGZfc2FsaXZhLndpZGUkdGltZV9DTVJfNStkZl9zYWxpdmEud2lkZSR0aW1lX1NNUl81KS8yLCBuYS5ybT1UUlVFKQojIE1ha2UgaW50byB3aWRlCmRmX3NhbGl2YS53aWRlX3N1YiA8LSBkZl9zYWxpdmEud2lkZSAlPiUgZHBseXI6OnNlbGVjdChzdWJqZWN0X251bWJlciwgQVVDZ19jb250cm9sOkhQQV9hY3QpIAoKIyBBZGQgdG8gdGhlIG1haW4gZGYKZGZfc2FsaXZhIDwtIG1lcmdlKGRmX3NhbGl2YSwgZGZfc2FsaXZhLndpZGVfc3ViLCBieT0ic3ViamVjdF9udW1iZXIiKSAKCiMgRmFjdG9yIHZhcmlhYmxlcyBhbmQgZmlsdGVyIG5vbiBuZWVkZWQgZGF0YQpkZl9zYWxpdmEkc2Nhbl90eXBlIDwtIGZhY3RvcihkZl9zYWxpdmEkc2Nhbl90eXBlLGxldmVscz1jKCJDb250cm9sIiwiU3RyZXNzIiksIGxhYmVscz1jKCJDb250cm9sIiwgIlN0cmVzcyIpKQpkZl9zYWxpdmEuc2NhbiA8LSBkZl9zYWxpdmEgJT4lIGZpbHRlcighaXMubmEoZmlyc3Rfc2NhbikpCmBgYAoKIyMjIEhlYXJ0IFJhdGUgey19CkhlYXJ0IHJhdGUgbWVhc3VyZXMgd2VyZSBjb2xsZWN0ZWQgdXNpbmcgYSBCcmFpbmFtcCBiYXNlZCBzeXN0ZW0uIFdlICBsb2FkIGluIHRoZSBoZWFydCByYXRlIGRhdGEsIGFuZCBzdGFydCBieSBjbGVhbmluZyBpdCB1cC4gVGhlIGFjdHVhbCBkZW5vaXNpbmcgYW5kIGFydGlmYWN0IHJlbW92YWwgaXMgZG9uZSBpbiBNYXRsYWIgdXNpbmcgSGVSYSAobWVudGlvbmVkIGFib3ZlKS4gRm9yIHRoaXMgYW5hbHlzaXMsIHdlIHNpbXBseSBpbXBvcnQgdGhlIGNvbGxlY3RlZCByZXN1bHRzIGZyb20gdGhpcyBwcm9ncmFtLCBhbmQgdGhlbiBwcm9jZWVkIHdpdGggYSBmZXcgc2ltcGxlIGNsZWFuaW5nIHN0ZXBzLiBGaXJzdCB3ZSBpbXBvcnQgdGhlIGRhdGEuIFRoZW4gd2UgY2xlYW4uIENlcnRhaW4gc3ViamVjdHMgaGF2ZSBpc3N1ZXMgd2l0aCB0aGUgbmFtaW5nIG9mIHRoZWlyIGZNUkkgRUVHIHJlY29yZGluZ3Mgb2YgSFIgZGF0YSAoZm9yIGV4YW1wbGUsIGR1ZSB0byBzdG9wcGluZyB0aGUgc2NhbiBhbmQgcmVzdGFydGluZywgb3IgYSBwcm9ncmFtIGNyYXNoKS4gU28gd2UgbmVlZCB0byBkbyBzb21lIGNsZWFuaW5nIGZvciB0aGUgbmFtZXMgYW5kIHNlc3Npb25zIGZvciBlYWNoIG9mIHRoZXNlIHN1YmplY3RzIGluZGl2aWR1YWxseS4gVGhpcyBpcyBkb25lIGJlbG93LiBJdHMgYSBsaXR0bGUgcnVkaW1lbnRhcnkgYnV0IHRoaXMgd2FzIGNvZGVkIGluIHRoZSBmaXJzdCBkYXlzIG9mIHVzaW5nIFIgYW5kIGl0cyB0b28gY3VtYmVyc29tZSB0byBlZGl0IG5vdy4gQmFzaWNhbGx5LCBpZiBpdCBhaW4ndCBicm9rZSwgZG9uJ3QgZml4IGl0LiBGaW5hbGx5LCB3ZSByZS1vcmRlciBvdXIgc2Vzc2lvbiBpbmRpY2F0b3JzLCBhbmQgZG91YmxlIGNoZWNrIHRvIG1ha2Ugc3VyZSB0aGV5IGFsbCBoYXZlIGZhY3RvcnMgdGhhdCBsZXQgdXMgcGxvdCBhbmQgYW5hbHlzZSB0aGUgZGF0YSBlZmZlY3RpdmVseS4KYGBge3J9CiMgTG9hZCBkYXRhCmRmX0hSIDwtIHJlYWQuY3N2KCJkYXRhL2ZtcmlfSFJfY2xlYW4uY3N2IikKIyBEcm9wIGR1cGxpY2F0ZXMKZGZfSFI8LWRmX0hSWyFkdXBsaWNhdGVkKGRmX0hSJEZpbGVfTmFtZSksXQoKI1N1YiAxMDoKZGZfSFIkUnVuW2RmX0hSJFNVQl9OUiA9PSAxMCAmIGRmX0hSJFJ1biA9PSA1XSA8LSA0CmRmX0hSJFJ1bltkZl9IUiRTVUJfTlIgPT0gMTAgJiBkZl9IUiRSdW4gPT0gMF0gPC0gNQpkZl9IUiRSdW5fdGltZVtkZl9IUiRTVUJfTlIgPT0gMTAgJiBkZl9IUiRSdW4gPT0gNF0gPC0gMjkKZGZfSFIkUnVuX3RpbWVbZGZfSFIkU1VCX05SID09IDEwICYgZGZfSFIkUnVuID09IDVdIDwtIDQ1CgojIFN1YiA1MiBzMV9yMSBlcnJvcnM6CmRmX0hSPC1kZl9IUlshKGRmX0hSJFNVQl9OUj09NTIgJiBkZl9IUiRSdW49PTEgJiBkZl9IUiRTZXNzaW9uPT0yKSxdCmRmX0hSJFJ1bltkZl9IUiRTVUJfTlIgPT0gNTIgJiBkZl9IUiRSdW4gPT0gMiAmIGRmX0hSJFNlc3Npb249PTJdIDwtIDEKZGZfSFIkUnVuW2RmX0hSJFNVQl9OUiA9PSA1MiAmIGRmX0hSJFJ1biA9PSAzICYgZGZfSFIkU2Vzc2lvbj09Ml0gPC0gMgpkZl9IUiRSdW5bZGZfSFIkU1VCX05SID09IDUyICYgZGZfSFIkUnVuID09IDQgJiBkZl9IUiRTZXNzaW9uPT0yXSA8LSAzCmRmX0hSJFJ1bltkZl9IUiRTVUJfTlIgPT0gNTIgJiBkZl9IUiRSdW4gPT0gNSAmIGRmX0hSJFNlc3Npb249PTJdIDwtIDQKZGZfSFIkUnVuW2RmX0hSJFNVQl9OUiA9PSA1MiAmIGRmX0hSJFJ1biA9PSAwICYgZGZfSFIkU2Vzc2lvbj09Ml0gPC0gNQoKIyBTVUI2NyAgU2Vzc2lvbiAyCmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWI2N19zMl9yMS0yX2ZNUklfcnVuXzFfVFIxNTAwbXNfMTg5dm9sc18tMTAtMjk0c19oZXJhLm1hdCJdIDwtIDIKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1YjY3X3MyX3IxLTJfZk1SSV9ydW5fMl9UUjE1MDBtc180NzV2b2xzXzYyOS0xMzYxc19oZXJhLm1hdCJdIDwtIDMKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1YjY3X3MyX3IxLTJfZk1SSV9ydW5fM19UUjE1MDBtc18yMDB2b2xzXzEzODAtMTcwMHNfaGVyYS5tYXQiXSA8LSA0CmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWI2N19zMl9yMS0yX2ZNUklfcnVuXzRfVFIxNTAwbXNfNDc1dm9sc18xNzMwLTI0NjJzX2hlcmEubWF0Il0gPC0gNQoKIyBTVUIgNzEgU2Vzc2lvbiAxCmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWJfNzFfczFfcjJfZk1SSV9ydW5fMV9UUjE1MDBtc180NzV2b2xzXzE2MS04OTNzX2hlcmEubWF0Il0gPC0gNgpkZl9IUiRSdW5bZGZfSFIkRmlsZV9OYW1lPT0ic3ViXzcxX3MxX3IyX2ZNUklfcnVuXzJfVFIxNTAwbXNfMjAwdm9sc185MTUtMTIzNXNfaGVyYS5tYXQiXSA8LSA3CmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWJfNzFfczFfcjJfZk1SSV9ydW5fM19UUjE1MDBtc180NzV2b2xzXzEyNjctMTk5OXNfaGVyYS5tYXQiXSA8LSA4CmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWJfNzFfczFfcjJfZk1SSV9ydW5fNF9UUjE1MDBtc18yMDB2b2xzXzIwMTktMjMzOXNfaGVyYS5tYXQiXSA8LSA5CmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWJfNzFfczFfcjJfZk1SSV9ydW5fNV9UUjE1MDBtc180NzV2b2xzXzIzNzEtMzEwM3NfaGVyYS5tYXQiXSA8LSAxMApkZl9IUiRTZXNzaW9uW2RmX0hSJFNlc3Npb249PTAgJiBkZl9IUiRTVUJfTlI9PTcxXSA8LSAyCgojIFNVQiA3MiBTZXNzaW9uIDEKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMV9yMV9mTVJJX3J1bl8yX1RSMTUwMG1zXzIwMHZvbHNfMjkwMC0zMjIwc19oZXJhLm1hdCJdPTIKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMV9yMV9mTVJJX3J1bl8zX1RSMTUwMG1zXzQ3NXZvbHNfMzYxNS00MzQ4c19oZXJhLm1hdCJdPTMKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMV9yMV9mTVJJX3J1bl80X1RSMTUwMG1zXzIwMHZvbHNfNDM5Ni00NzE2c19oZXJhLm1hdCJdPTQKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMV9yMV9mTVJJX3J1bl81X1RSMTUwMG1zXzQ3NXZvbHNfNDc2NC01NDk3c19oZXJhLm1hdCJdPTUKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMV9yMl9mTVJJX3J1bl8xX1RSMTUwMG1zXzQ3NXZvbHNfMTc2LTkwOHNfaGVyYS5tYXQiXT02CmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWJfNzJfczFfcjJfZk1SSV9ydW5fMl9UUjE1MDBtc18yMDB2b2xzXzk0NC0xMjY0c19oZXJhLm1hdCJdID03CmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWJfNzJfczFfcjJfZk1SSV9ydW5fM19UUjE1MDBtc180NzV2b2xzXzEyODktMjAyMXNfaGVyYS5tYXQiXT04CmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWJfNzJfczFfcjJfZk1SSV9ydW5fNF9UUjE1MDBtc18yMDB2b2xzXzIwNDktMjM2OXNfaGVyYS5tYXQiXT05CmRmX0hSJFJ1bltkZl9IUiRGaWxlX05hbWU9PSJzdWJfNzJfczFfcjJfZk1SSV9ydW5fNV9UUjE1MDBtc180NzV2b2xzXzI0MDktMzE0MnNfaGVyYS5tYXQiXT0xMApkZl9IUiRTZXNzaW9uW2RmX0hSJFJ1bj4wICYgZGZfSFIkU1VCX05SPT03Ml0gPC0gMQojIFNVQiA3MiBTZXNzaW9uIDIKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMl9yMV9mTVJJX3J1bl8xX1RSMTUwMG1zXzQ3NXZvbHNfMTAwNS0xNzM3c19oZXJhLm1hdCJdPTEKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMl9yMV9mTVJJX3J1bl8yX1RSMTUwMG1zXzIwMHZvbHNfMTc2OC0yMDg4c19oZXJhLm1hdCJdPTIKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMl9yMV9mTVJJX3J1bl8zX1RSMTUwMG1zXzQ3NXZvbHNfMjQyMS0zMTU0c19oZXJhLm1hdCJdPTMKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMl9yMV9mTVJJX3J1bl80X1RSMTUwMG1zXzIwMHZvbHNfMzE3MS0zNDkxc19oZXJhLm1hdCJdPTQKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMl9yMV9mTVJJX3J1bl81X1RSMTUwMG1zXzQ3NXZvbHNfMzUwNS00MjM4c19oZXJhLm1hdCJdPTUKZGZfSFIkUnVuW2RmX0hSJEZpbGVfTmFtZT09InN1Yl83Ml9zMl9yMl9mTVJJX3J1bl8xX1RSMTUwMG1zXzQ3NXZvbHNfMzc0LTExMDZzX2hlcmEubWF0Il09NgpkZl9IUiRSdW5bZGZfSFIkRmlsZV9OYW1lPT0ic3ViXzcyX3MyX3IyX2ZNUklfcnVuXzJfVFIxNTAwbXNfMjAwdm9sc18xMTMzLTE0NTNzX2hlcmEubWF0Il09NwpkZl9IUiRSdW5bZGZfSFIkRmlsZV9OYW1lPT0ic3ViXzcyX3MyX3IyX2ZNUklfcnVuXzNfVFIxNTAwbXNfNDc1dm9sc18xNTI2LTIyNThzX2hlcmEubWF0Il09OApkZl9IUiRSdW5bZGZfSFIkRmlsZV9OYW1lPT0ic3ViXzcyX3MyX3IyX2ZNUklfcnVuXzRfVFIxNTAwbXNfMjAwdm9sc18yMzM3LTI2NTdzX2hlcmEubWF0Il09OQpkZl9IUiRSdW5bZGZfSFIkRmlsZV9OYW1lPT0ic3ViXzcyX3MyX3IyX2ZNUklfcnVuXzVfVFIxNTAwbXNfNDc1dm9sc18yNjg2LTM0MThzX2hlcmEubWF0Il09MTAKZGZfSFIkU2Vzc2lvbltkZl9IUiRTZXNzaW9uPT0wICYgZGZfSFIkU1VCX05SPT03Ml0gPC0gMgoKIyBOb3cgcmVtb3ZlIGFueXRoaW5nIGV4dHJhIHRoYXQgd2FzbnQgY2xlYW5lZCB1cDoKZGZfSFIkUnVuW2RmX0hSJFJ1bj09MF0gPC0gTkEKCiMgRmFjdG9yIHRvIGluZGljYXRlIGxhdGUgYW5kIGVhcmx5CmRmX0hSJHRpbWVfcG9pbnQgPC0gMSAKZGZfSFIkdGltZV9wb2ludFtkZl9IUiRSdW4gPiA1XSA8LSAyCmRmX0hSJHRpbWVfcG9pbnQgPC0gZmFjdG9yKGRmX0hSJHRpbWVfcG9pbnQsIGxldmVscz1jKCcxJywnMicpLCAgIGxhYmVscz1jKCdFYXJseScsJ0xhdGUnKSkKCiMgRmFjdGlyIGZpciB2YXJpYWJsZSBmb3Igc3RyZXNzIGFuZCBjb250cm9sCmRmX0hSJFNlc3Npb24gPC0gZmFjdG9yKGRmX0hSJFNlc3Npb24sIGxldmVscz1jKCcxJywnMicpLCBsYWJlbHM9YygnQ29udHJvbCcsJ1N0cmVzcycpKQoKIyBMZXRzIGFsc28gYWRkIHRoZSBmaXJzdCBzY2FuIGNvbG91bW4gZnJvbSBjYXN0b3I6CmRmX0hSX0ZpcnN0IDwtIGRmX2Nhc3RvcgpkZl9IUl9GaXJzdCA8LSBzZXBhcmF0ZShkZl9IUl9GaXJzdCwgc3ViamVjdF9udW1iZXIsIGMoImxlYWRfdmFsIiwgIlNVQl9OUiIpLCBzZXA9Il8iKQpkZl9IUl9GaXJzdCRTVUJfTlIgPC0gYXMuaW50ZWdlcihkZl9IUl9GaXJzdCRTVUJfTlIpCmRmX0hSIDwtIG1lcmdlKGRmX0hSLCBkZl9IUl9GaXJzdCwgYnk9IlNVQl9OUiIsIGFsbD1UKQpkZl9IUiRmaXJzdF9zY2FuIDwtIHBhc3RlKGRmX0hSJGZpcnN0X3NjYW4sICJGaXJzdCIsIHNlcD0iLSIpCmRmX0hSIDwtIGRwbHlyOjpmaWx0ZXIoZGZfSFIsICFpcy5uYShmaXJzdF9zY2FuKSkKCiNNYWtlIFNlcGFyYXRlIGRmIGZvciBlYXJseSBhbmQgbGF0ZQpkZl9IUl9FYXJseSA8LSBzdWJzZXQoZGZfSFIsIHRpbWVfcG9pbnQ9PSdFYXJseScpCmRmX0hSX0xhdGUgPC0gc3Vic2V0KGRmX0hSLCB0aW1lX3BvaW50PT0nTGF0ZScpCmRmX0hSX0Vhcmx5JFJ1bl90aW1lW2RmX0hSX0Vhcmx5JFJ1bl90aW1lPT0xXSA8LSA2CgojIENsZWFuIG5hbWVzCmRmX0hSIDwtIGRmX0hSICU+JSBjbGVhbl9uYW1lcygpICU+JSBmaWx0ZXIoZmlyc3Rfc2NhbiE9Ik5BLUZpcnN0IikKZGZfSFIkc3ViamVjdF9udW1iZXIgPC0gcGFzdGUoInN1YiIsIHN0cl9wYWQoZGZfSFIkc3ViX25yLCAzLCBwYWQgPSAiMCIpLCBzZXA9Il8iKQpkZl9IUiA8LSBtZXJnZShkZl9IUiwgZGZfZGVtb2dyYXBoaWNzLCBieT0ic3ViamVjdF9udW1iZXIiKSAlPiUgZHBseXI6OnJlbmFtZShmaXJzdF9zY2FuPSJmaXJzdF9zY2FuLngiKQpgYGAKCgojIyBTdGF0aXN0aWNzCk5vdyB0aGF0IHdlIGhhdmUgY2xlYW5lZCB1cCBvdXIgcGh5c2lvbG9neSBkYXRhLCB3ZSBjYW4gc3RhcnQgd2l0aCB0aGUgYWN0dWFsIHN0YXRpc3RpY3Mgb2YgaW50ZXJlc3QuIFRoZSBnb2FsIGhlcmUgaXMgdG8gZXN0YWJsaXNoIGluY3JlYXNlZCBwaHlzaW9sb2dpY2FsIGFyb3VzYWwvc3RyZXNzIGluIHRoZSBzdHJlc3Mgc2Vzc2lvbiByZWxhdGl2ZSB0byB0aGUgY29udHJvbC4gV2UgZmlyc3QgdGFrZSBhIGxvb2sgYXQgcmVsZXZhbnQgc2FsaXZhIG1lYXN1cmVzIChpLmUuLCBjb3J0aXNvbCBhbmQgYWxwaGEgYW15bGFzZSksIGFuZCB0aGVuIHRoZSBoZWFydCByYXRlIG1lYXN1cmVzICh1c2luZyBJQkkgYW5kIFJNU1NEKS4gIAoKIyMjIENvcnRpc29sIHstIC50YWJzZXR9CldlIGZpcnN0IGNoZWNrIHRoZSBkYXRhIGRpc3RyaWJ1dGlvbiwgd2hpY2ggbG9va3MgbGlrZSBpdCBuZWVkcyBhIGxvZyB0cmFuc2Zvcm1hdGlvbi4gV2UgdGhlbiBydW4gYSBtb2RlbCwgd2l0aCB0aGUgYWRkaXRpb24gb2YgdGltZSwgYW5kIGNvbnRyb2xsaW5nIGZvciBzY2FuIG9yZGVyIGVmZmVjdHMuIFdlIHNlZSBpbiBvdXIgbWFpbiBtb2RlbCB0aGF0IHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgc3RyZXNzKnRpbWUgZWZmZWN0IG9uIGNvcnRpc29sLiBXZSBydW4gYSBmb2xsb3ctdXAgb24gdGhlIGluaXRpYWwgbW9kZWwgdG8gY2hlY2sgdGhlIGluZGl2aWR1YWwgdGltZSBlZmZlY3RzLiBXZSBzZWUgdGhhdCB0aGF0IGR1cmluZyB0aGUgZWFybHkgc3RyZXNzIHBoYXNlLCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGluY3JlYXNlIGluY3JlYXNlIGluIGNvcnRpc29sIGxldmVscy4gV2Ugc2VlIHRoYXQgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIGNvcnRpc29sIGJldHdlZW4gdGhlIHN0cmVzcyBhbmQgY29udHJvbCBzZXNzaW9ucywgYW5kIGF0IHNwZWNpZmljIHBvaW50cyBpbiB0aGUgZm9sbG93IHVwLiAKClNpbmNlIHdlIHdhbnQgdG8gdXNlIGEgc2luZ2xlIG1ldHJpYyBpbiB0aGUgZk1SSSBhbmFseXNpcyBmb3IgdGhlIHJlc3BvbnNlIGFzIGEgbW9kdWxhdG9yLCB3ZSBjaGVjayB0aGUgYXJlYSB1bmRlciB0aGUgY3VydmUgKEFVQykgYmV0d2VlbiB0aGUgdHdvIHRpbWUgcG9pbnRzLiBXZSBkbyB0aGlzIHdpdGggYSBwYWlyZWQgc2FtcGxlIHQtdGVzdCBzaW5jZSBpdHMgdGhlIGRpZmZlcmVuY2UgaW4gYSBzaW5nbGUgbWVhc3VyZSB3ZSBhcmUgdGVzdGluZyBoZXJlLiBXZSBzZWUgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBBVUNpIGJldHdlZW4gdGhlIHNlc3Npb25zLiBXZSBhbHNvIHRlc3QgYW4gYWx0ZXJuYXRpdmUgbWV0aG9kIGZvciBiYXNlbGluZSBjb3JyZWN0aW9ucyAodGhlIEhlbmNrZW5zIHJlc3BvbnNlKS4gVG8gdGVzdCBpZiB0aGVyZSBpcyBhbiBpbmNyZWFzZSBpbiBjb3J0aXNvbCBpbiB0aGUgc3RyZXNzIHNlc3Npb24sIHRoaXMgdmFsdWUgc2hvdWxkIGJlIHBvc2l0aXZlIChzdHJlc3MtY29udHJvbC9iYXNlbGluZSkuIElmIHN0cmVzcy1jb250cm9sIGlzID4gMCwgdGhlbiB0aGUgc3RyZXNzIHdvcmsuIFNvIHdlIHVzZSBhIG9uZS1zYW1wbGUgdC10ZXN0IGFnYWluc3QgMCB0byBjaGVjayBpZiBpdCB3b3JrcyBoZXJlLgoKIyMjIyBIaXN0LiB7LX0KYGBge3J9Cmhpc3QoZGZfc2FsaXZhLnNjYW4kY29ydGlzb2wpCmhpc3QobG9nKGRmX3NhbGl2YS5zY2FuJGNvcnRpc29sKSkKYGBgCgoKIyMjIyBNYWluIEVmZmVjdHMgey0gLmFjdGl2ZX0KYGBge3J9Cm1vZGVsLmNvcnRfc2NhbiA8LSBnbG1lcihjb3J0aXNvbCB+IHNjYW5fdHlwZSp0aW1lKmZpcnN0X3NjYW4gKyBzZXggKyAoMStzY2FuX3R5cGV8c3ViamVjdF9udW1iZXIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseT1HYW1tYShsaW5rPSJsb2ciKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGdsbWVyQ29udHJvbChjYWxjLmRlcml2cyA9RkFMU0UpLAogICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3Qoc2Nhbl90eXBlPSJjb250ci50cmVhdG1lbnQiLCBzZXg9ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9zYWxpdmEuc2NhbikKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVsLmNvcnRfc2Nhbiwgc2hvdy5zdGF0PVRSVUUsIHNob3cuc2U9VFJVRSwgdHJhbnNmb3JtPU5VTEwpJGtuaXRyKQpjaGVja19tb2RlbChtb2RlbC5jb3J0X3NjYW4pCmBgYAoKIyMjIyBQb3N0LUhvYyB7LX0KYGBge3J9CmRmX3NhbGl2YS5zY2FuJHJ1biA8LSBhcy5mYWN0b3IoZGZfc2FsaXZhLnNjYW4kdGltZV9wb2ludCkKbW9kZWwuY29ydF9zY2FuX2ZvbGxvd3VwIDwtIGdsbWVyKGNvcnRpc29sIH4gc2Nhbl90eXBlKnJ1biArIHNjYW5fdHlwZSpmaXJzdF9zY2FuICsgc2V4ICsgKDErc2Nhbl90eXBlfHN1YmplY3RfbnVtYmVyKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChzY2FuX3R5cGU9ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5PUdhbW1hKGxpbms9ImxvZyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGdsbWVyQ29udHJvbChjYWxjLmRlcml2cyA9RkFMU0UpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9zYWxpdmEuc2NhbikKZW1tZWFucyhtb2RlbC5jb3J0X3NjYW5fZm9sbG93dXAsIGxpc3QocGFpcndpc2UgfiBzY2FuX3R5cGUqcnVuKSxieT1jKCJydW4iKSwgYWRqdXN0PSJub25lIikKYGBgCgojIyMjIFBvc3QtSG9jOiBTZXgvQ29udHJhY2VwdGl2ZSB7LX0KCmBgYHtyfQptb2RlbC5jb3J0X3NjYW5fY29udHIgPC0gZ2xtZXIoY29ydGlzb2wgfiBzY2FuX3R5cGUqdGltZSpmaXJzdF9zY2FuICsgY29udHJhY2VwdGl2ZV91c2UgKyAoMStzY2FuX3R5cGV8c3ViamVjdF9udW1iZXIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseT1HYW1tYShsaW5rPSJsb2ciKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGdsbWVyQ29udHJvbChjYWxjLmRlcml2cyA9RkFMU0UpLAogICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3Qoc2Nhbl90eXBlPSJjb250ci50cmVhdG1lbnQiLCBjb250cmFjZXB0aXZlX3VzZT0iY29udHIudHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX3NhbGl2YS5zY2FuKQphc2lzX291dHB1dCh0YWJfbW9kZWwobW9kZWwuY29ydF9zY2FuX2NvbnRyLCBzaG93LnN0YXQ9VFJVRSwgc2hvdy5zZT1UUlVFLCB0cmFuc2Zvcm09TlVMTCkka25pdHIpCmNoZWNrX21vZGVsKG1vZGVsLmNvcnRfc2Nhbl9jb250cikKYGBgCgoKIyMjIyBBVUNpIHstfQpgYGB7cn0KZGZfc2FsaXZhLndpZGVfc3ViIDwtIGRmX3NhbGl2YS5zY2FuICU+JSBkcGx5cjo6c2VsZWN0KHN1YmplY3RfbnVtYmVyLCBhZ2UsIHNleCwgY29udHJhY2VwdGl2ZV91c2UsIGZpcnN0X3NjYW4sIEFVQ2dfY29udHJvbDpIUEFfYWN0KSAlPiUgdW5pcXVlKCkgCmRlc2NyaWJlKGRmX3NhbGl2YS53aWRlJEFVQ2lfZGlmZmVyZW5jZTwwKQptb2RlbC5hdWMgPC0gbG0oQVVDaV9zdHJlc3MgLSBBVUNpX2NvbnRyb2wgfiAxICsgZmlyc3Rfc2NhbiArIHNleCwgZGF0YT1kZl9zYWxpdmEud2lkZV9zdWIpCnN1bW1hcnkobW9kZWwuYXVjKQpgYGAKCiMjIyMgSFBBIFJlc3BvbnNlIHstfQpgYGB7cn0KbW9kZWwuaHBhIDwtIGxtKEhQQV9hY3QgfiAxICsgZmlyc3Rfc2NhbiArIHNleCwgZGF0YT1kZl9zYWxpdmEud2lkZV9zdWIpCnN1bW1hcnkobW9kZWwuaHBhKQpgYGAKCiMjIyMgUGxvdCB7LX0KYGBge3J9CiMgTWFrZSBTdW1tYXJ5CmRmX3NhbGl2YS5zdW1tIDwtIHN1bW1hcnlTRXdpdGhpbihkYXRhPWRmX3NhbGl2YS5zY2FuLCBpZHZhciA9InN1YmplY3RfbnVtYmVyIiwgd2l0aGludmFycyA9Yygic2Nhbl90eXBlIiwgInRpbWVfcG9pbnQiKSwgbWVhc3VyZXZhciA9ICJjb3J0aXNvbCIsIG5hLnJtPVRSVUUpCmRmX3NhbGl2YS5zdW1tJHRpbWVfcG9pbnQgPC0gYXMuY2hhcmFjdGVyKGRmX3NhbGl2YS5zdW1tJHRpbWVfcG9pbnQpICU+JSBhcy5udW1lcmljKGRmX3NhbGl2YS5zdW1tJHRpbWVfcG9pbnQpCgojQ29uc3RydWN0IHRoZSBwbG90CnBsb3QuY29ydF90aW1lIDwtIGdncGxvdChkZl9zYWxpdmEuc3VtbSwgYWVzKHk9Y29ydGlzb2wsIHg9dGltZV9wb2ludCwgIGNvbG91cj1zY2FuX3R5cGUpKSArCiAgIyBBZGQgdGhlIHNjYW4gcGhhc2VzCiAgZ2VvbV9yZWN0KGFlcyh4bWluPTMsIHhtYXg9MTAsIHltaW49MywgeW1heD02LjIsIGNvbG9yPU5VTEwpLCBmaWxsPSIjRTY4NjEzIiwgYWxwaGE9MC4wMikgKwogIGdlb21fcmVjdChhZXMoeG1pbj0xOCwgeG1heD04NCwgeW1pbj0zLCB5bWF4PTYuMiwgY29sb3I9TlVMTCksIGZpbGw9ImxpZ2h0Z3JleSIsIGFscGhhPTAuMDIpICsKICBnZW9tX3JlY3QoYWVzKHhtaW49OTEsIHhtYXg9MTU3LCB5bWluPTMsIHltYXg9Ni4yICwgIGNvbG9yPU5VTEwpLGZpbGw9ImxpZ2h0Z3JleSIsIGFscGhhPTAuMDIpICsKICAjIEFjdGlhbCBwbG90CiAgZ2VvbV9saW5lKHNpemU9MSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWNvcnRpc29sLXNlLCB5bWF4PWNvcnRpc29sK3NlKSxzaXplPTEsIHdpZHRoPTMsIG5hLnJtPVQpICsKICBnZW9tX3BvaW50KHNoYXBlPTIwLCBzaXplPTMpICsgCiAgIyBTY2FsZSB0byBtYWtlIHRoZSBncmFwaCBzdGFydCBhdCAzCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMywgTkEpKSArCiAgIyBUaXRsZXMgYW5kIGxhYmVscwogIGxhYnMoY29sb3VyPSJTZXNzaW9uIiwgZmlsbD0iUGhhc2UiKSsKICB4bGFiKCJUaW1lIChtaW51dGVzKSIpICsgeWxhYigiQ29ydGlzb2wgKG5tb2wvTClcbiIpICsKICBnZ3RoZW1lMiArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c3RyZXNzX2NvbG9ycykKCiNQbG90IHdpdGggdGltZSAKcGxvdC5jb3J0X3RpbWU7IGdnc2F2ZShmaWxlbmFtZT0iZmlndXJlcy9GaWd1cmVfM19MYWJTdHJlc19BLnN2ZyIsIGRldmljZT0ic3ZnIiwgcGxvdCA9IHBsb3QuY29ydF90aW1lLCBkcGk9MzAwLCBiZz0id2hpdGUiKSAjCmBgYAoKIyMjIEFteWxhc2Ugey0gLnRhYnNldH0KSW4gYWRkaXRpb24gdG8gdGhlIGNvcnRpc29sLCB3ZSBhbHNvIGFzc2F5ZWQgdGhlIGxldmVscyBvZiBhbHBoYSBhbXlsYXNlLCB3aGljaCBpcyB1c2VkIGEgcHJveHkgZm9yIGFkcmVuYWxpbmUuIFdlIGZpcnN0IHRha2UgYSBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2Ygb3VyIHZhcmlhYmxlIHRvIHNlZSBpZiB3ZSBuZWVkIHRvIGRvIGFueSB0cmFuc2Zvcm1hdGlvbnMgdG8gaXQgYmVmb3JlIG1vZGVsaW5nLCBhbmQgdGhlbiBwcm9jZWVkIHRvIGRvIHRoZSBtb2RlbHMgaW4gdGhlIHNhbWUgd2F5IHdlIGRpZCBmb3IgdGhlIGNvcnRpc29sIG1lYXN1cmVzLiBXZSBzZWUgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIGlzIGEgYml0IG9mZiwgYW5kIHRoYXQgd2UgbmVlZCB0byBhcHBseSBhIGxvZyB0cmFuc2Zvcm1hdGlvbiB0byBnZXQgYmV0dGVyIGZpdCBpbiBvdXIgbW9kZWxzLiAKCkluIHRoZSBtYWluIGVmZmVjdHMgb2Ygb3VyIG1vZGVscywgd2Ugc2VlIHRoYXQgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBlZmZlY3Qgb2YgdGltZSwgYW5kIHRoYXQgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBpbnRlcmFjdGlvbiBiZXR3ZWVuIHNjYW4gb3JkZXIgYW5kIHRoZSBzdHJlc3MgZWZmZWN0cy4gV2UgaW52ZXN0aWdhdGUgdGhpcyBpbiBmb2xsb3ctdXAgbW9kZWxzLCBhbmQgc2VlIHRoYXQgaW4gcGVvcGxlIHdobyBoYWQgYSBzdHJlc3Mgc2Vzc2lvbiBmaXJzdCwgdGhlIGhlYXJ0IHJhdGUgd2FzIGhpZ2hlciBpbiB0aGUgc3RyZXNzIHRoYW4gY29udHJvbCBzZXNzaW9ucywgYnV0IG5vdCBpbiB0aG9zZSB3aG8gaGFkIHRoZSBjb250cm9sIHNlc3Npb24gZmlyc3QuIFdlIGdvIG9uIHRvIHBsb3QgdGhpcyBlZmZlY3QuCgojIyMjIEhpc3QuIHstfQpgYGB7cn0KI2hpc3QoZGZfc2FsaXZhLnNjYW4kYWxwaGFfYW15bGFzZSkKaGlzdChsb2coZGZfc2FsaXZhLnNjYW4kYWxwaGFfYW15bGFzZSkpCmBgYAoKIyMjIyBNYWluIEVmZmVjdHMgey0gLmFjdGl2ZX0KYGBge3J9Cm1vZGVsLmFteWxhc2Vfc2NhbiA8LSBnbG1lcihhbHBoYV9hbXlsYXNlIH4gc2Nhbl90eXBlKnRpbWUqZmlyc3Rfc2NhbiArIHNleCArICgxK3NjYW5fdHlwZXxzdWJqZWN0X251bWJlciksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3Qoc2Nhbl90eXBlPSJjb250ci50cmVhdG1lbnQiLCBzZXg9ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseT1HYW1tYShsaW5rPSJsb2ciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBnbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGQUxTRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9zYWxpdmEuc2NhbikKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVsLmFteWxhc2Vfc2Nhbiwgc2hvdy5zZT1UUlVFLCBzaG93LnN0YXQ9VFJVRSwgdHJhbnNmb3JtPU5VTEwpJGtuaXRyKQpjaGVja19tb2RlbChtb2RlbC5hbXlsYXNlX3NjYW4pCmBgYAoKCgojIyMjIFBvc3QtSG9jIHstfQpgYGB7cn0KbW9kZWwuYW15bGFzZV9zY2FuLmZ1IDwtIGdsbWVyKGFscGhhX2FteWxhc2UgfiBzY2FuX3R5cGUqcnVuICsgc2Nhbl90eXBlKmZpcnN0X3NjYW4gKyBzZXggKygxK3NjYW5fdHlwZXxzdWJqZWN0X251bWJlciksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3Qoc2Nhbl90eXBlPSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHk9R2FtbWEobGluaz0ibG9nIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRkFMU0UpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfc2FsaXZhLnNjYW4pCmVtbWVhbnMobW9kZWwuYW15bGFzZV9zY2FuLmZ1LCBwYWlyd2lzZSB+IGZpcnN0X3NjYW4qc2Nhbl90eXBlLCBhZGp1c3Q9Im5vbmUiKQojZW1taXAobW9kZWwuYW15bGFzZV9zY2FuLmZ1LCB+IHNjYW5fdHlwZSpmaXJzdF9zY2FuKQpgYGAKCiMjIyMgUGxvdCB7LX0KYGBge3J9CiMgTWFrZSBTdW1tYXJ5CmRmX3NhbGl2YS5zdW1tX2FteSA8LSAgc3VtbWFyeVNFd2l0aGluKGRhdGE9ZGZfc2FsaXZhLnNjYW4sIGlkdmFyID0ic3ViamVjdF9udW1iZXIiLCB3aXRoaW52YXJzID1jKCJzY2FuX3R5cGUiLCAidGltZV9wb2ludCIpLCBiZXR3ZWVudmFycyA9ICJmaXJzdF9zY2FuIiwgbWVhc3VyZXZhciA9ICJhbHBoYV9hbXlsYXNlIiwgbmEucm09VFJVRSkKZGZfc2FsaXZhLnN1bW1fYW15JHRpbWVfcG9pbnQgPC0gYXMuY2hhcmFjdGVyKGRmX3NhbGl2YS5zdW1tX2FteSR0aW1lX3BvaW50KSAlPiUgYXMubnVtZXJpYyhkZl9zYWxpdmEuc3VtbV9hbXkkdGltZV9wb2ludCkKCiNDb25zdHJ1Y3QgdGhlIHBsb3QKcGxvdC5hbXlsYXNlX3RpbWUgPC0gZ2dwbG90KGRmX3NhbGl2YS5zdW1tX2FteSAsIGFlcyh5PWFscGhhX2FteWxhc2UsIHg9dGltZV9wb2ludCwgY29sb3VyPXNjYW5fdHlwZSkpICsKICBnZW9tX2xpbmUoc2l6ZT0xLHN0YXQgPSAiaWRlbnRpdHkiLCBuYS5ybSA9IFRSVUUsIHNob3cubGVnZW5kID0gVFJVRSkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49YWxwaGFfYW15bGFzZS1zZSwgeW1heD1hbHBoYV9hbXlsYXNlK3NlKSxzaXplPTEsIHdpZHRoPTMsIG5hLnJtPVQpICsgCiAgZ2VvbV9wb2ludChzaGFwZT0yMCwgc2l6ZT0zKSArIAogIGdlb21fcmVjdChtYXBwaW5nPWFlcyh4bWluPTMsIHhtYXg9MTIsIHltaW49NTAsIHltYXg9MTUwLCBmaWxsPSdncmV5JyksIGZpbGw9ICdsaWdodGdyZXknLGNvbG9yPSdsaWdodGdyZXknLCBhbHBoYT0wLjA1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKCkrIyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwgNiwgMTgsIDUwLCAxMDApKSsKICBnZ3RpdGxlKCJTYWxpdmFyeSBBbXlsYXNlIER1cmluZyBTY2FubmluZyIpK2xhYnMoY29sb3VyPSJTZXNzaW9uIikrCiAgeGxhYigiVGltZSAobWludXRlcykiKSArIHlsYWIoIkFteWxhc2UgKG5tb2wvTClcbiIpKyAKICBnZ3RoZW1lMiArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c3RyZXNzX2NvbG9ycykKI1Bsb3Qgd2l0aCBlcnJvciBiYXRzIGFuZCBtYXJraW5nIHNpZ25pZmljYW50IGRpZmZlcmVuY2VzCnBsb3QuYW15bGFzZV90aW1lICsgZmFjZXRfZ3JpZCgufmZpcnN0X3NjYW4pCmBgYAoKIyMjIElCSSB7LSAudGFic2V0fQpOb3cgd2UgY2FuIGxvb2sgYXQgdGhlIGNoYW5nZXMgaW4gdGhlIElCSSBhcyBhIGZ1bmN0aW9uIG9mIHN0cmVzcy4gV2UgZXhwZWN0IHRoZSBJQkkgdG8gYmUgaW5jcmVhc2VkIGZvbGxvd2luZyB0aGUgc3RyZXNzIGluZHVjdGlvbi4gSGVyZSwgd2UgYW5hbHl6ZSB0aGUgZWZmZWN0cyBvZiBhY3Jvc3MgdGhlIDEwIHNjYW5uZXIgcnVucyBvdXIgcGFydGljaXBhbnRzIGhhZCAoaW5jbHVkaW5nIHRoZSByZXN0aW5nIHN0YXRlIHJ1bnMpLkluIHRoZSBtb2RlbHMsIHdlIGFnYWluIGluY2x1ZGUgdGhlIHNjYW4gb3JkZXIgYXMgYSBmaXhlZCBlZmZlY3QgaW4gdGhlIHNhbWUgd2F5IHdlIGRpZCBmb3IgdGhlIGNvcnRpc29sIGFuYWx5c2lzLgoKVGhlcmUgaXMgYSBzaWduaWZpY2FudCBtYWluIGVmZmVjdCBvZiB0aW1lLCBhIHR3by13YXkgaW50ZXJhY3Rpb24gYmV0d2VlbiBzdHJlc3MgYW5kIHNjYW4gb3JkZXIsIGFuZCB0aHJlZS13YXkgaW50ZXJhY3Rpb24gYmV0d2VlbiBzdHJlc3MgZWZmZWN0cywgdGltZSwgYW5kIHNjYW4gb3JkZXIuIEEgZm9sbG93LXVwIHNob3dzIHRoYXQgdGhlIHN0cmVzcyBlZmZlY3QgaXMgb25seSBwcmVzZW50IGluIHRob3NlIHdobyBoYXZlIHRoZSBzdHJlc3Mgc2Vzc2lvbiBmaXJzdCwgCgojIyMjIE1haW4gRWZmZWN0cyB7LSAuYWN0aXZlfQpgYGB7cn0gCiMgSUJJIExpbmVhciBNb2RlbAptb2RlbC5JQklfc2NhbiA8LSBsbWVyKGliaSB+IHNlc3Npb24qcnVuKmZpcnN0X3NjYW4gKyBzZXggKyAoc2Vzc2lvbnxzdWJfbnIpLAogICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KHNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIsIHNleD0iY29udHIudHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9IUikKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVsLklCSV9zY2FuLCBzaG93LnNlPVQsIHNob3cuc3RhdD1UKSRrbml0cikKY2hlY2tfbW9kZWwobW9kZWwuSUJJX3NjYW4pCmBgYAoKIyMjIyBQb3N0LUhvYyB7LX0KYGBge3J9CmRmX0hSJFJ1biA8LSBhcy5mYWN0b3IoZGZfSFIkcnVuKQptb2RlbC5pYmlfc2Nhbi5mdSA8LSBsbWVyKGliaSB+IHNlc3Npb24qUnVuKmZpcnN0X3NjYW4gKyBzZXggKyAoc2Vzc2lvbnxzdWJfbnIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3Qoc2Vzc2lvbj0iY29udHIudHJlYXRtZW50Iiwgc2V4PSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfSFIgKQplbW1lYW5zKG1vZGVsLmliaV9zY2FuLmZ1LCBsaXN0KHBhaXJ3aXNlIH4gc2Vzc2lvbipmaXJzdF9zY2FuKSxieT1jKCJmaXJzdF9zY2FuIiksIGFkanVzdD0ibm9uZSIpCmVtbWVhbnMobW9kZWwuaWJpX3NjYW4uZnUsIGxpc3QocGFpcndpc2UgfiBzZXNzaW9uKlJ1biksYnk9YygiZmlyc3Rfc2NhbiIsICJSdW4iKSwgYWRqdXN0PSJub25lIikKYGBgCgojIyMjIFBsb3Qgey19CmBgYHtyfQojIE1ha2UgU3VtbWFyeQpkZl9IUi5zdW1tIDwtIHN1bW1hcnlTRXdpdGhpbihkYXRhPWRmX0hSLCBpZHZhciA9InN1Yl9uciIsIHdpdGhpbnZhcnMgPWMoInNlc3Npb24iLCAicnVuIiksIGJldHdlZW52YXJzID0gImZpcnN0X3NjYW4iLCBtZWFzdXJldmFyID0gImliaSIsIG5hLnJtPVRSVUUpCmRmX0hSLnN1bW0gPC0gbmEub21pdChkZl9IUi5zdW1tKQpkZl9IUi5zdW1tJHJ1biA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkZl9IUi5zdW1tJHJ1bikpCmRmX0hSLnN1bW0kUGhhc2UgPC0gaWZlbHNlKGRmX0hSLnN1bW0kcnVuPDYsICJFYXJseSIsICJMYXRlIikKCiNDb25zdHJ1Y3QgdGhlIHBsb3QKcGxvdC5pYmlfdGltZSA8LSBnZ3Bsb3QoZGZfSFIuc3VtbSwgYWVzKHk9aWJpLCB4PXJ1biwgY29sb3I9c2Vzc2lvbikpICsKICAjIE1ha2UgdGhlIGJhY2tncm91bmQgc2Vzc2lvbiBzcXVhcmVzCiAgZ2VvbV9yZWN0KGFlcyh4bWluPTAsIHhtYXg9MC42LCB5bWluPTYyLCB5bWF4PTcyLCBjb2xvcj1OVUxMKSwgZmlsbD0iI0U2ODYxMyIsIGFscGhhPTAuMDIpICsKICBnZW9tX3JlY3QoYWVzKHhtaW49MC44LCB4bWF4PTUuMiwgeW1pbj02MiwgeW1heD03MiwgY29sb3I9TlVMTCksIGZpbGw9ImxpZ2h0Z3JleSIsIGFscGhhPTAuMDIpICsKICBnZW9tX3JlY3QoYWVzKHhtaW49NS44LCB4bWF4PTEwLjIsIHltaW49NjIsIHltYXg9NzIgLCAgY29sb3I9TlVMTCksZmlsbD0ibGlnaHRncmV5IiwgYWxwaGE9MC4wMikgKwogICMgQWN0dWFsIFBsb3QKICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIsIHNob3cubGVnZW5kID0gVFJVRSkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49aWJpLXNlLCB5bWF4PWliaStzZSksIHdpZHRoPTAuMjUsIG5hLnJtPVQpICsKICBnZW9tX3BvaW50KHNoYXBlPTIwLCBzaXplPTIsIGxpbmU9MikgKyAKICAjIExlZ2VuIHRpdGxlcyBhbmQgc3VjaAogIGxhYnMoY29sb3VyPSJTZXNzaW9uIiwgZmlsbD0iU2Vzc2lvbiIpKwogIHhsYWIoIiIpICsgeWxhYigiSGVhcnQgUmF0ZSAoQlBNKSIpKyAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzLDQsNSw2LDcsOCw5LDEwKSkgKyAKICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKG9yZGVyPTIpKSArCiAgZ2d0aGVtZTIgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXN0cmVzc19jb2xvcnMgKSAgIysgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImxpZ2h0Z3JleSIsICJsaWdodGdyZXkiLCApKQojcGxvdC5pYmlfdGltZQpwbG90LmliaV90aW1lICsgZmFjZXRfZ3JpZChmaXJzdF9zY2Fufi4pCmBgYAoKIyMjIFJNU1NEIHstIC50YWJzZXR9Ck5vdyB3ZSBjYW4gdGFrZSBhIGxvb2sgYXQgdGhlIFJNU1NEIHZhbHVlcy4gRmlyc3Qgd2UgY2hlY2sgdGhlIGRpc3RyaWJ1dGlvbiB0byBhaWQgd2l0aCBtb2RlbCBkZWNpc2lvbnMgYW5kIHRoZW4gcnVuIHRoZSBtb2RlbHMuIFRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgdGltZSBieSBzZXNzaW9uIGVmZmVjdCBoZXJlLCB3aXRoIGEgc2lnbmlmaWNhbnQgZWZmZWN0IG9mIHNjYW4gb3JkZXIgb24gdGhlIHNlc3Npb24gZWZmZWN0LiBXZSBzZWUgdGhhdCBpbiBwZW9wbGUgd2hvIGhhZCBhIHN0cmVzcyBzZXNzaW9uIGZpcnN0LCB0aGVyZSBpcyBhbiBvdmVyYWxsIGxvd2VyIFJNU1NEIGluIHRoZSBzdHJlc3Mgc2Vzc2lvbi4gIAoKIyMjIyBIaXN0LiB7LX0KYGBge3J9Cmhpc3QobG9nKGRmX0hSJHJ0bXNzZCkpCmBgYAoKIyMjIyBNYWluIEVmZmVjdHMgey0gLmFjdGl2ZX0KYGBge3J9Cm1vZGVsLnJtc3NkX3NjYW4gPC0gZ2xtZXIocnRtc3NkIH4gc2Vzc2lvbipydW4qZmlyc3Rfc2NhbiArIHNleCArIChzZXNzaW9ufHN1Yl9uciksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KHNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIsIHNleD0iY29udHIudHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX0hSLAogICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5PUdhbW1hKGxpbms9ImxvZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbD1nbG1lckNvbnRyb2woY2FsYy5kZXJpdnM9RkFMU0UpKQoKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVsLnJtc3NkX3NjYW4sIHNob3cuc3RhdD1UUlVFLCBzaG93LnNlPVRSVUUsIHRyYW5zZm9ybT1OVUxMLCBkaWdpdHMgPTMgKSRrbml0cikKY2hlY2tfbW9kZWwobW9kZWwucm1zc2Rfc2NhbikKYGBgCgoKCiMjIyMgUG9zdC1Ib2Mgey19CmBgYHtyfQpkZl9IUiRSdW4gPC0gYXMuZmFjdG9yKGRmX0hSJHJ1bikKbW9kZWwucm1zc2Rfc2Nhbi5mdSA8LSBnbG1lcihydG1zc2QgfiBzZXNzaW9uKlJ1bipmaXJzdF9zY2FuICsgc2V4ICsgKHNlc3Npb258c3ViX25yKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KHNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9IUiwKICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseT1HYW1tYShsaW5rPSJsb2ciKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9Z2xtZXJDb250cm9sKGNhbGMuZGVyaXZzPUZBTFNFLCBvcHRpbWl6ZXIgPSJib2J5cWEiKSkKZW1tZWFucyhtb2RlbC5ybXNzZF9zY2FuLmZ1LCBsaXN0KHBhaXJ3aXNlIH4gc2Vzc2lvbipmaXJzdF9zY2FuKSxieT1jKCJmaXJzdF9zY2FuIiksIGFkanVzdD0ibm9uZSIpCmVtbWVhbnMobW9kZWwucm1zc2Rfc2Nhbi5mdSwgbGlzdChwYWlyd2lzZSB+IHNlc3Npb24qUnVuKSxieT1jKCJSdW4iKSwgYWRqdXN0PSJub25lIikKYGBgCgojIyMjIFBsb3R7LX0KYGBge3J9CiMgTWFrZSBTdW1tYXJ5CmRmX0hSLnN1bW0gPC0gc3VtbWFyeVNFd2l0aGluKGRhdGE9ZGZfSFIsIGlkdmFyID0ic3ViX25yIiwgd2l0aGludmFycyA9Yygic2Vzc2lvbiIsICJydW4iKSxiZXR3ZWVudmFycyA9ImZpcnN0X3NjYW4iLCBtZWFzdXJldmFyID0gInJ0bXNzZCIsIG5hLnJtPVRSVUUpCmRmX0hSLnN1bW0gPC0gbmEub21pdChkZl9IUi5zdW1tKQpkZl9IUi5zdW1tJHJ1biA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkZl9IUi5zdW1tJHJ1bikpCgojQ29uc3RydWN0IHRoZSBwbG90CnBsb3QucnRtc3NkX3RpbWUgPC0gZ2dwbG90KGRmX0hSLnN1bW0sIGFlcyh5PXJ0bXNzZCwgeD1ydW4sIGNvbG91cj1zZXNzaW9uKSkgKwogICMgTWFrZSB0aGUgYmFja2dyb3VuZCBzZXNzaW9uIHNxdWFyZXMKICBnZW9tX3JlY3QoYWVzKHhtaW49MCwgeG1heD0wLjYsIHltaW49NDcsIHltYXg9NzIsIGNvbG9yPU5VTEwpLCBmaWxsPSIjRTY4NjEzIiwgYWxwaGE9MC4wMikgKwogIGdlb21fcmVjdChhZXMoeG1pbj0wLjgsIHhtYXg9NS4yLCB5bWluPTQ3LCB5bWF4PTcyLCBjb2xvcj1OVUxMKSwgZmlsbD0ibGlnaHRncmV5IiwgYWxwaGE9MC4wMikgKwogIGdlb21fcmVjdChhZXMoeG1pbj01LjgsIHhtYXg9MTAuMiwgeW1pbj00NywgeW1heD03MiAsICBjb2xvcj1OVUxMKSxmaWxsPSJsaWdodGdyZXkiLCBhbHBoYT0wLjAyKSArCiAgIyBBZGQgbGFiZWxzCiAgIyBnZW9tX2xhYmVsKGFlcyh4PTAuNCwgeT03NSwgbGFiZWw9IlNFQ1BUIiksIGNvbG9yPSJibGFjayIpICsKICAjIGdlb21fbGFiZWwoYWVzKHg9MywgeT03NSwgbGFiZWw9IkVhcmx5IiksIGNvbG9yPSJibGFjayIpICsKICAjIGdlb21fbGFiZWwoYWVzKHg9OCwgeT03NSwgbGFiZWw9IkxhdGUiKSwgY29sb3I9ImJsYWNrIikgKwogICMgQWN0dWFsIFBsb3QKICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIsIHNob3cubGVnZW5kID0gVFJVRSkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49cnRtc3NkLXNlLCB5bWF4PXJ0bXNzZCtzZSksIHdpZHRoPTAuMjUsIG5hLnJtPVQpICsKICBnZW9tX3BvaW50KHNoYXBlPTIwLCBzaXplPTIsIGxpbmU9MikgKyAKICBsYWJzKGNvbG91cj0iU2Vzc2lvbiIsIGZpbGw9IlNlc3Npb24iKSsKICB4bGFiKCJTY2FubmVyIFJ1biIpICsgeWxhYigiUk1TU0QgKG1zKSIpICsgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxLDIsMyw0LDUsNiw3LDgsOSwxMCkpICtzY2FsZV95X2NvbnRpbnVvdXMobi5icmVha3MgPSA1KSArCiAgZ2d0aGVtZTIgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXN0cmVzc19jb2xvcnMpCnBsb3QucnRtc3NkX3RpbWUgKyBmYWNldF9ncmlkKGZpcnN0X3NjYW5+LikgCmBgYAoKIyMjIEZ1bGwgUGxvdCB7LX0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3QucGh5c2lvX2Z1bGwgPC0gZ2dhcnJhbmdlKHBsb3QuY29ydF90aW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dhcnJhbmdlKE5VTEwsIChwbG90LmliaV90aW1lICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NikpICsgZmFjZXRfZ3JpZChmaXJzdF9zY2Fufi4pKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5VTEwsIChwbG90LnJ0bXNzZF90aW1lICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NikpKyBmYWNldF9ncmlkKGZpcnN0X3NjYW5+LikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sPTIsIG5yb3c9MiwgbGVnZW5kPSJub25lIiwgYWxpZ24gPSAiaHYiLCBsYWJlbHMgPSBjKCJCIiwgTkEsICJDIiwgTkEpLCB3aWR0aHM9YygwLjEsMSkpLCAKICAgICAgICAgIGNvbW1vbi5sZWdlbmQgPSBULCBsZWdlbmQ9ImJvdHRvbSIsIHdpZHRocz1jKDEuNSwgMSksIGxhYmVscz1jKCJBIikpCmBgYAoKYGBge3J9CiMgSSBzZXBhcmF0ZWQgdGhpcyBjaHVuayBiZWNhdXNlIGdnYXJyYW5nZSB3YXMgcHJvZHVjaW5nIGEgcmFuZG9tIGJsYW5rIHBsb3QKcGxvdC5waHlzaW9fZnVsbApnZ3NhdmUoImZpZ3VyZXMvRmlndXJlXzNfTGFiU3RyZXNzLnN2ZyIsIGRwaT0zMDAsIGRldmljZT0ic3ZnIiwgYmc9IndoaXRlIiwgd2lkdGggPTgpCmBgYAoKCiMgZk1SSTogTGFyZ2Utc2NhbGUgbmV0d29ya3MgdW5kZXIgc3RyZXNzCldlIGhhdmUgbm93IHZhbGlkYXRlZCBvdXIgc3RyZXNzIGV4cG9zdXJlIHBhcmFkaWdtcyBpbiBib3RoIHRoZSBsYWIgYW5kIHJlYWwgbGlmZS4gV2Ugd2VyZSBhbHNvIGFibGUgdG8gZGVyaXZlIGEgc2luZ2xlIG1lYXN1cmUgZnJvbSBlYWNoIG9mIHRoZSBzdHJlc3MgZXhwb3N1cmUgcGFyYWRpZ21zIHdlIGhhdmUuIFRoYXQgaXMsIHdlIGhhdmUgdGhlIEFVQ2kgYXMgb3VyIGluZGljYXRvciBvZiBsYWIgc3RyZXNzIHJlYWN0aXZpdHksIGFuZCBvdXIgcmVzaWR1YWwgYmFzZWQgc3RyZXNzIHNjb3JlIGZvciB0aGUgcmVhbC1saWZlIGRhdGEuIFdlIGNhbiBpbmNvcnBvcmF0ZSB0aGVzZSB0d28gbWVhc3VyZXMgaW50byBvdXIgZk1SSSBhbmFseXNpcy4gV2UgZG8gdGhpcyBpbiB0d28gd2F5czogR0xNcyBpbiB0aGUgRlNMIHNvZnR3YXJlIHRvb2wgYm94LCBhbmQgbW9kZWxzIGhlcmUgaW4gUiBmb3Igb3VyIFJPSSBiYXNlZCBhbmFseXNpcy4gCgpCZWZvcmUgd2Ugc3RhcnQgdGhpcyBhbmFseXNpcyB0aG91Z2gsIHdlIGRvIHNvbWUgc2lnbmFsIGV4cGxvcmF0aW9uIGJlbG93LiBXZSBkZXNjcmliZSBicmllZmx5IGluIHRoZSBbSW50cm9kdWN0aW9uXSgpIHdoYXQgdGFza3Mgd2VyZSB1c2VkLCBidXQgbm90IHRoZSBlbnRpcmV0eSBvZiB0aGUgZk1SSSBkZXNpZ24uIEluIHN1bW1hcnksIG91ciBwYXJ0aWNpcGFudHMgdW5kZXJ3ZW50IGEgc3RyZXNzIGFuZCBjb250cm9sIGZNUkkgc2Vzc2lvbi4gVGhlc2Ugc2Vzc2lvbnMgY29uc2lzdGVkIG9mIHR3byBoYWx2ZXMsIGVhY2ggd2l0aCAzIHJ1bnMuIFRoZSB0aHJlZSBydW5zIGluIGVhY2ggaGFsZiBhcmUgbW9kZWxlZCBhdCB0aGUgZmlyc3QgbGV2ZWwgaW4gRlNMIHRvIGVuZCB1cCB3aXRoIGZvdXIgZk1SSSBzZXNzaW9ucyBwZXIgcGFydGljaXBhbnQuIFRoZSBmaXJzdCB0aHJlZSBydW5zIGNvbnNpc3Qgb2YgdGhlIGVhcmx5IHBoYXNlLCB3aGlsZSB0aGUgbGFzdCB0aHJlZSBjb25zaXN0IG9mIHRoZSBsYXRlIHBoYXNlLiBUaGlzIHJlc3VsdHMgaW46IAoKLSBDb250cm9sIEVhcmx5Ci0gQ29udHJvbCBMYXRlCi0gU3RyZXNzIEVhcmx5Ci0gU3RyZXNzIExhdGUKClRoaXMgZGVzaWduIGdpdmVzIHVzIGluc2lnaHQgaW50byB0aGUgdGVtcG9yYWwgZHluYW1pY3Mgb2Ygc3RyZXNzIHJlYWN0aXZpdHkgYW5kIHJlY292ZXJ5LiBXZSBmaXJzdCBleHBsb3JlIHRoZSBtZWFuIHRhc2sgcmVsYXRlZCBhY3Rpdml0eSBhY3Jvc3MgYWxsIGZvdXIgc2Vzc2lvbnMsIGFuZCB0aGVuIGV4YW1pbmUgdGhlIHN0cmVzcyBlZmZlY3RzIChzdHJlc3MtY29udHJvbCkuIFRoZXNlIGVmZmVjdHMgYXJlIG1vZGVsZWQgYXQgdGhlIHN1YmplY3QgbGV2ZWwgaW4gRlNMLiBGb3IgYm90aCB0aGUgbWVhbiB0YXNrIGFuZCB0aGUgc3RyZXNzIHJlbGF0ZWQgZGlmZmVyZW5jZXMsIHdlIGhhdmUgdHdvIGNvbnRyYXN0cy4gVGhlIGJhc2VsaW5lIGNvbnRyYXN0IG1vZGVscyB0aGUgbWVhbiB0YXNrIGFjdGl2aXR5IHJlbGF0aXZlIHRvIHRoZSBpbXBsaWNpdCBiYXNlbGluZSwgd2hpbGUgdGhlIHRhc2sgcmVsYXRlZCBjb250cmFzdHMgbW9kZWxzIHRoZSB0YXNrIHJlbGF0ZWQgYWN0aXZpdHkgZHVyaW5nIHRoZSBzcGVjaWZpYyB0YXNrLCByZWxhdGl2ZSB0byB0aGUgYWN0aXZpdHkgZHVyaW5nIHRoZSBvdGhlciB0YXNrcy4gVGhpcyBsYXR0ZXIgY29udHJhc3QgaXMgdGhlIG1haW4gb25lIHdlIGFyZSBpbnRlcmVzdGVkIGluLCBhcyBpdCBzcGVjaWZpY2FsbHkgcmVmbGVjdHMgdGhlIG5ldHdvcmsgcmVzb3VyY2UgYWxsb2NhdGlvbnMuIApgYGB7cn0KIyBMb2FkIGRhdGEKZGZfZm1yaS5zaWduYWwgPC1yZWFkLmNzdigiL3Byb2plY3QvMzAxMzA2OC4wMi9zdGF0cy9mTVJJL1NpZ25hbC9mTVJJX3NpZ25hbF9ldmVudF9zdHJlc3NfenN0YXQudHh0Iiwgc2VwPSdcdCcsIGhlYWRlcj1UKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoc3ViX25yLCBjb3BlKSAlPiUgZGlzdGluY3QoTWFzayxSdW4sIC5rZWVwX2FsbD1UUlVFKSAlPiUgdW5ncm91cCAlPiUgZHBseXI6Om11dGF0ZShOZXR3b3JrPU1hc2spICU+JSAKICBkcGx5cjo6bXV0YXRlKENvbnRyYXN0PXN0cl9yZXBsYWNlKGNvcGUsICJjb3BlMSIsICIyQmFjayIpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgQ29udHJhc3Q9c3RyX3JlcGxhY2UoQ29udHJhc3QsICJjb3BlMiIsICJOb0JhY2siKSwKICAgICAgICAgICAgICAgIENvbnRyYXN0PXN0cl9yZXBsYWNlKENvbnRyYXN0LCAiY29wZTMiLCAiMkJhY2s+Tm9CYWNrIiksIAogICAgICAgICAgICAgICAgQ29udHJhc3Q9c3RyX3JlcGxhY2UoQ29udHJhc3QsICJjb3BlNCIsICJPZGRiYWxsIiksCiAgICAgICAgICAgICAgICBDb250cmFzdD1zdHJfcmVwbGFjZShDb250cmFzdCwgImNvcGU1IiwgIk5vZGRiYWxsIiksCiAgICAgICAgICAgICAgICBDb250cmFzdD1zdHJfcmVwbGFjZShDb250cmFzdCwgImNvcGU2IiwgIk9kZD5Ob2RkIiksCiAgICAgICAgICAgICAgICBDb250cmFzdD1zdHJfcmVwbGFjZShDb250cmFzdCwgImNvcGU3IiwgIk1lbS1SZW0iKSwKICAgICAgICAgICAgICAgIENvbnRyYXN0PXN0cl9yZXBsYWNlKENvbnRyYXN0LCAiY29wZTgiLCAiTWVtLUZvciIpLAogICAgICAgICAgICAgICAgQ29udHJhc3Q9c3RyX3JlcGxhY2UoQ29udHJhc3QsICJjb3BlOSIsICJSZW0+Rm9yIiksCiAgICAgICAgICAgICAgICBDb250cmFzdD1zdHJfcmVwbGFjZShDb250cmFzdCwgIjJCYWNrMCIsICJFQ04tQ29uIiksCiAgICAgICAgICAgICAgICBDb250cmFzdD1zdHJfcmVwbGFjZShDb250cmFzdCwgIjJCYWNrMSIsICJTTi1Db24iKSwKICAgICAgICAgICAgICAgIENvbnRyYXN0PXN0cl9yZXBsYWNlKENvbnRyYXN0LCAiMkJhY2syIiwgIkRNTi1Db24iKSwKICAgICAgICAgICAgICAgIENvbnRyYXN0PXN0cl9yZXBsYWNlKENvbnRyYXN0LCAiMkJhY2szIiwgIjJCYWNrK05vQmFjayIpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoQ29udHJhc3Q9IGZhY3RvcihDb250cmFzdCwgbGV2ZWxzPWMoIjJCYWNrIiwgIk5vQmFjayIsICIyQmFjaz5Ob0JhY2siLCAiRUNOLUNvbiIsICIyQmFjaytOb0JhY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT2RkYmFsbCIsICJOb2RkYmFsbCIsICJPZGQ+Tm9kZCIsIlNOLUNvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWVtLVJlbSIsICJNZW0tRm9yIiwgIlJlbT5Gb3IiLCAiRE1OLUNvbiIpKSkKCiMgRmlsdGVyIGZvciBwbG90cyBhbmQgYXZlcmFnZSB0ZXN0cwpkZl9mbXJpLnNpZ25hbF9tZWFuIDwtIGRmX2Ztcmkuc2lnbmFsICU+JSBmaWx0ZXIoUnVuPT0iTWVhbiIpCmRmX2Ztcmkuc2lnbmFsX2V2ZW50IDwtIGRmX2Ztcmkuc2lnbmFsICU+JSBmaWx0ZXIoUnVuIT0iTWVhbiIpCmBgYAoKV2Ugd2lsbCBhbHNvIHRyeSB0byBsaW5rIHRoZSBsYWJvcmF0b3J5IHN0cmVzcyBtZWFzdXJlLCB0byB0aGUgcmVhbC1saWZlIG1lYXN1cmUuIFdlIHRoZW4gdHJ5IHRvIHNlZSBob3cgZWl0aGVyIG9mIHRoZXNlIGNvdWxkIGJlIHJlbGF0ZWQgdG8gb3VyIGxhcmdlIHNjYWxlIG5ldHdvcmsgYmFsYW5jZS4gSW4gb3JkZXIgdG8gZG8gc28sIHdlIG5lZWQgdG8gcGVyZm9ybSBzb21lIGRhdGEgY2xlYW5pbmcsIHdoZXJlIHdlIGFkZCBhbGwgdGhlIGRhdGEgb2YgaW50ZXJlc3QgdG9nZXRoZXIuIFdlIG5lZWQgdG8gY29tYmluZSB0aGUgZk1SSSwgdGhlIGNvcnRpc29sLCBhbmQgdGhlIHN0cmVzcy1iYXNlZCByZXNpZHVhbCB0b2dldGhlciBpbnRvIG9uZSBkYXRhIGZyYW1lLiBXZSBhbHNvIHNhdmUgYSBkYXRhIGZyYW1lIHdpdGgganVzdCB0aHJlZSBjb2x1bW5zOiBzdWJqZWN0IG51bWJlciwgY29ydGlzb2wsIGFuZCB0aGUgcmVzaWR1YWxpemVkIHNjb3JlIHRvIHVzZSBpbiBGU0wgZGlyZWN0bHkuIApgYGB7cn0KIyBNZXJnZSB0aGUgZGF0YWZyYW1lcyB0byBpbmNsdWRlIHRoZSBzdHJlc3MgcmVhY3Rpdml0eSBtZWFzdXJlcwpkZl9jb21ibyA8LSBtZXJnZShkZl9zdHJlc3NyeCwgZGZfc2FsaXZhLndpZGVfc3ViLCBieS54PSJpZCIsIGJ5Lnk9InN1YmplY3RfbnVtYmVyIikgCmRmX2NvbWJvLmZtcmkgPC0gZGZfZm1yaS5zaWduYWxfZXZlbnQKZGZfY29tYm8uZm1yaSRpZCA8LSBwYXN0ZSgic3ViIiwgKHN0cl9wYWQoZGZfY29tYm8uZm1yaSRzdWJfbnIsIDMsIHBhZCA9ICIwIikpLCBzZXA9Il8iKSAKZGZfY29tYm8gPC0gbWVyZ2UoZGZfY29tYm8sIGRmX2NvbWJvLmZtcmksIGJ5PSJpZCIpCgoKIyBSZXNjYWxlIGFuZCBjZW50ZXIgZGF0YSBwb2ludHMgZm9yIG1vZGVsaW5nCiMjIENvcnRpc29sCmRmX2NvbWJvJEhQQV9hY3RbaXMubmEoZGZfY29tYm8kSFBBX2FjdCldIDwtIG1lYW4oZGZfY29tYm8kSFBBX2FjdCwgbmEucm09VCkKZGZfY29tYm8kQVVDaV9kaWZmZXJlbmNlW2lzLm5hKGRmX2NvbWJvJEFVQ2lfZGlmZmVyZW5jZSldIDwtIG1lYW4oZGZfY29tYm8kQVVDaV9kaWZmZXJlbmNlLCBuYS5ybT1UKQojIyBSZXNjYWxlCmRmX2NvbWJvIDwtIGRmX2NvbWJvICU+JSBzdWJzZXQoISBpcy5uYShTaWduYWwpKSAlPiUgZHBseXI6Om11dGF0ZShIUEFfYWN0X3o9c2NhbGUoSFBBX2FjdCwgY2VudGVyPVRSVUUpLCBzdHJlc3Nfcnhfej1zY2FsZShyZXNCSU4sIGNlbnRlcj1UUlVFKSwgc2lnbmFsX3o9c2NhbGUoU2lnbmFsLCBjZW50ZXI9VFJVRSksIEFVQ2lfZGlmZl96PXNjYWxlKEFVQ2lfZGlmZmVyZW5jZSwgY2VudGVyPVRSVUUpKQpkZl9jb21ibyA8LSBhcy5kYXRhLmZyYW1lKGRmX2NvbWJvKQojIENvbnRyYXN0IHNldHRpbmdzCmRmX2NvbWJvJHNleCA8LSBhcy5mYWN0b3IoZGZfY29tYm8kc2V4KQpjb250cmFzdHMoZGZfY29tYm8kc2V4KSA8LSBjb250ci50cmVhdG1lbnQoYygiRmVtYWxlIiwgIk1hbGUiKSkKZGZfY29tYm8kY29udHJhY2VwdGl2ZV91c2UgPC0gYXMuZmFjdG9yKGRmX2NvbWJvJGNvbnRyYWNlcHRpdmVfdXNlKQpjb250cmFzdHMoZGZfY29tYm8kY29udHJhY2VwdGl2ZV91c2UpIDwtIGNvbnRyLnRyZWF0bWVudChjKCJNYWxlIiwgIk5vIiwgIlllcyIpKQojIyBTYXZlIGFzIGRhdGFmcmFtZSBmb3IgZk1SSSB3aG9sZSBicmFpbiBhbmFseXNpcwpkZl9jb21iby50b3NhdmUgPC0gZGZfY29tYm8gJT4lIGRwbHlyOjpzZWxlY3Qoc3ViX25yLCBzdHJlc3NfcnhfeiwgSFBBX2FjdF96LCBBVUNpX2RpZmZfeikgJT4lIHVuaXF1ZSgpCndyaXRlLmNzdjIoZGZfY29tYm8udG9zYXZlLCAiZGF0YS9mTVJJX3JlZ3Jlc3Nvci50eHQiLCBkZWM9Ii4iICkKYGBgCgoKIyMgTWVhbiBUYXNrIEVmZmVjdHMgey50YWJzZXR9CkhlcmUgd2UgY2hlY2sgZm9yIHRoZSBtYWluIHRhc2sgZWZmZWN0cyBmb3Igb3VyIDJCYWNrIChFQ04pLCBPZGRiYWxsIChTTiksIGFuZCBSZXRyaWV2YWwgKERNTikgY29udHJhc3RzLiBUbyBkbyB0aGlzLCB3ZSBwbG90IHRoZSBtZWFuIHNpZ25hbCBmcm9tIGVhY2ggdGhlIHRhc2tzIGFjcm9zcyBuZXR3b3Jrcy4gV2hhdCB3ZSB3b3VsZCBpZGVhbGx5IGxpa2UgdG8gc2VlIGlzIHRoZSByZWNydWl0bWVudCBvZiB0aGUgY29ycmVzcG9uZGluZyBuZXR3b3JrLXRhc2sgY29tYmluYXRpb25zLiBXaGlsZSB3ZSBkbyBzZWUgdGhpcyBpbiB0aGUgRUNOIGFuZCBTTiBjb250cmFzdHMsIHdlIGRvIG5vdCByZWFsbHkgZ2V0IHRoaXMgZWZmZWN0IGZvciB0aGUgRE1OLiAKCiMjIyBFQ046IDJCYWNrIHstfQpgYGB7cn0KIyBGaWx0ZXIgYW5kIGdlbmVyYXRlIHN1bW1hcnkKZGZfZm1yaS4yYmFjayA8LSBkZl9jb21ibyAlPiUgc3Vic2V0KGNvcGU9PSJjb3BlMSIgfCBjb3BlPT0iY29wZTIiIHwgY29wZT09ImNvcGUzIikKZGZfZm1yaS4yYmFjayA8LSBzdW1tYXJ5U0V3aXRoaW4oZGF0YT1kZl9mbXJpLjJiYWNrLCBpZHZhcj0ic3ViX25yIiwgbWVhc3VyZXZhcj0iU2lnbmFsIiwgd2l0aGludmFycyA9IGMoIk5ldHdvcmsiLCAiY29wZSIsICJDb250cmFzdCIpKQphc2lzX291dHB1dCh0YWJfbW9kZWwobG1lcihTaWduYWwgfiAxICsgc2V4KyAoMXxpZCksIGRhdGE9KGRmX2NvbWJvJT4lIHN1YnNldChjb3BlPT0iY29wZTMiICYgTmV0d29yaz09IkVDTiIpKSkpJGtuaXRyKQojIE1ha2UgcGxvdApwbG90X2ZtcmkubWVhbl9lY24gPC0gZ2dwbG90KGRmX2ZtcmkuMmJhY2sgLCBhZXMoeT1TaWduYWwsIHg9TmV0d29yaywgY29sb3I9TmV0d29yaywgZmlsbD1OZXR3b3JrLCBuYS5ybSA9IFRSVUUpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBhbHBoYT0wLjUsIHBvc2l0aW9uPSJkb2RnZTIiICkgKwogICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVNpZ25hbC1zZSwgeW1heD1TaWduYWwrc2UsIGNvbG9yPU5ldHdvcmspLHNpemU9MSwgd2lkdGg9MC41LCBuYS5ybT1ULCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSguOSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgY29sb3I9ImdyZXkiKSArCiAgZ2d0aXRsZSgiUGFyYW1ldGVyIEVzdGltYXRlcyBvZiBUYXNrLU5ldHdvcmsgRW5nYWdlbWVudCIpICsgeWxhYigiUC5FLiIpICsgeGxhYigiICIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1mbXJpX2NvbG9ycykgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Zm1yaV9jb2xvcnMpICsgCiAgZ2d0aGVtZTIgKyB0aGVtZShheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT0xMiksIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksIGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiKQpwbG90X2ZtcmkubWVhbl9lY24gICsgZmFjZXRfd3JhcChDb250cmFzdH4uLCBuY29sPTMpCmBgYAoKCiMjIyBTTjogT2RkYmFsbCB7LX0KYGBge3J9CiMgU3Vic2V0ICsgTW9kZWwKZGZfZm1yaS5vZGQgPC0gZGZfY29tYm8gJT4lIHN1YnNldChjb3BlPT0iY29wZTQiIHwgY29wZT09ImNvcGU1IiB8IGNvcGU9PSJjb3BlNiIpCmRmX2Ztcmkub2RkIDwtIHN1bW1hcnlTRXdpdGhpbihkYXRhPWRmX2Ztcmkub2RkLCBpZHZhcj0ic3ViX25yIiwgbWVhc3VyZXZhcj0iU2lnbmFsIiwgd2l0aGludmFycyA9IGMoIk5ldHdvcmsiLCAiY29wZSIsICJDb250cmFzdCIpKQphc2lzX291dHB1dCh0YWJfbW9kZWwobG1lcihTaWduYWwgfiAxICsgc2V4ICsgKDF8aWQpLCBkYXRhPShkZl9jb21ibyU+JSBzdWJzZXQoY29wZT09ImNvcGU2IiAmIE5ldHdvcms9PSJTTiIpKSkpJGtuaXRyKQojIFBsb3QKcGxvdF9mbXJpLm1lYW5fc24gPC0gZ2dwbG90KGRmX2Ztcmkub2RkLCBhZXMoeT1TaWduYWwsIHg9TmV0d29yaywgY29sb3I9TmV0d29yaywgZmlsbD1OZXR3b3JrLCBuYS5ybSA9IFRSVUUpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBhbHBoYT0wLjUsIHBvc2l0aW9uPSJkb2RnZTIiICkgKwogICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVNpZ25hbC1zZSwgeW1heD1TaWduYWwrc2UsIGNvbG9yPU5ldHdvcmspLHNpemU9MSwgd2lkdGg9MC41LCBuYS5ybT1ULCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSguOSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgY29sb3I9ImdyZXkiKSArCiAgZ2d0aXRsZSgiUGFyYW1ldGVyIEVzdGltYXRlcyBvZiBUYXNrLU5ldHdvcmsgRW5nYWdlbWVudCIpICsgeWxhYigiUC5FLiIpICsgeGxhYigiICIpKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWZtcmlfY29sb3JzKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1mbXJpX2NvbG9ycykgKyAKICBnZ3RoZW1lMiArIHRoZW1lKGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3QgPSAwKSwgbGVnZW5kLnBvc2l0aW9uPSJyaWdodCIpCnBsb3RfZm1yaS5tZWFuX3NuICAgKyBmYWNldF93cmFwKENvbnRyYXN0fi4pCmBgYAoKIyMjIERNTjogTWVtb3J5IHstfQpgYGB7cn0KIyBTdWJzZXQgKyBNb2RlbApkZl9mbXJpLm1lbSA8LSBkZl9jb21ibyAlPiUgc3Vic2V0KGNvcGU9PSJjb3BlNyIgfCBjb3BlPT0iY29wZTgiIHwgY29wZT09ImNvcGU5IikgCmRmX2ZtcmkubWVtIDwtIHN1bW1hcnlTRXdpdGhpbihkYXRhPWRmX2ZtcmkubWVtLCBpZHZhcj0ic3ViX25yIiwgbWVhc3VyZXZhcj0iU2lnbmFsIiwgd2l0aGludmFycyA9IGMoIk5ldHdvcmsiLCAiY29wZSIsICJDb250cmFzdCIpKQphc2lzX291dHB1dCh0YWJfbW9kZWwobG1lcihTaWduYWwgfiAxICsgc2V4ICsgKDF8aWQpLCBkYXRhPShkZl9jb21ibyU+JSBzdWJzZXQoY29wZT09ImNvcGU5IiAmIE5ldHdvcms9PSJETU4iKSkpKSRrbml0cikKIyBQbG90CnBsb3RfZm1yaS5tZWFuX2RtbiA8LSBnZ3Bsb3QoZGZfZm1yaS5tZW0sIGFlcyh5PVNpZ25hbCwgeD1OZXR3b3JrLCBjb2xvcj1OZXR3b3JrLCBmaWxsPU5ldHdvcmssIG5hLnJtID0gVFJVRSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGFscGhhPTAuNSwgcG9zaXRpb249ImRvZGdlMiIgKSArCiAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49U2lnbmFsLXNlLCB5bWF4PVNpZ25hbCtzZSwgY29sb3I9TmV0d29yayksc2l6ZT0xLCB3aWR0aD0wLjUsIG5hLnJtPVQsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBjb2xvcj0iZ3JleSIpICsKICBnZ3RpdGxlKCJQYXJhbWV0ZXIgRXN0aW1hdGVzIG9mIFRhc2stTmV0d29yayBFbmdhZ2VtZW50IikgKyB5bGFiKCJQLkUuIikgKyB4bGFiKCIgIikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWZtcmlfY29sb3JzKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1mbXJpX2NvbG9ycykgKyAKICBnZ3RoZW1lMiArIHRoZW1lKGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3QgPSAwKSwgbGVnZW5kLnBvc2l0aW9uPSJyaWdodCIpCnBsb3RfZm1yaS5tZWFuX2RtbiAgICsgZmFjZXRfd3JhcChDb250cmFzdH4uKQpgYGAKCiMjIyBST0ktVGFzayBQYWlycyB7LSAuYWN0aXZlfQpgYGB7cn0KZGZfZm1yaS5tZWFuIDwtIGRmX2NvbWJvICU+JSBzdWJzZXQoKGNvcGU9PSJjb3BlMyIgJiBOZXR3b3JrPT0iRUNOIikgfCAoY29wZT09ImNvcGU2IiAmIE5ldHdvcms9PSJTTiIpIHwgKGNvcGU9PSJjb3BlOSIgJiBOZXR3b3JrPT0iRE1OIikpCmRmX2ZtcmkubWVhbl9zdW0gPC0gc3VtbWFyeVNFd2l0aGluKGRhdGE9ZGZfZm1yaS5tZWFuLCBpZHZhcj0ic3ViX25yIiwgbWVhc3VyZXZhcj0iU2lnbmFsIiwgd2l0aGludmFycyA9IGMoIk5ldHdvcmsiLCAiY29wZSIsICJDb250cmFzdCIpKQpkZl9mbXJpLm1lYW5fc3VtJENvbnRyYXN0IDwtIGZhY3RvcihkZl9mbXJpLm1lYW5fc3VtJENvbnRyYXN0KQoKcGxvdC5mbXJpX21lYW4gPC0gZ2dwbG90KGRmX2ZtcmkubWVhbl9zdW0sIGFlcyh5PVNpZ25hbCwgeD1OZXR3b3JrLCBjb2xvcj1Db250cmFzdCwgZmlsbD1Db250cmFzdCwgbmEucm0gPSBUUlVFKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgYWxwaGE9MC41LCBwb3NpdGlvbj0iZG9kZ2UyIiwgd2lkdGg9MC43ICkgKwogICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPVNpZ25hbC1zZSwgeW1heD1TaWduYWwrc2UpLHNpemU9MSwgd2lkdGg9MC40LCBuYS5ybT1ULCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSguOSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgY29sb3I9ImdyZXkiKSArCiAgZ2d0aXRsZSgiUGFyYW1ldGVyIEVzdGltYXRlcyBvZiBUYXNrLU5ldHdvcmsgRW5nYWdlbWVudCIpICsgeWxhYigiUGFyYW1ldGVyIEVzdGlhbXRlcyIpICsgeGxhYigiXG5ST0kiKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzBDQjcwMiIsICIjRjg3NjZEIiwgIiMwMEJGQzQiKSkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzBDQjcwMiIsICIjRjg3NjZEIiwgIiMwMEJGQzQiICkpICsgCiAgZ2d0aGVtZTIgKyAKICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdCA9IDApLCBsZWdlbmQucG9zaXRpb249InJpZ2h0IiwgCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMiwgY29sb3VyPSJibGFjayIpKQpwbG90LmZtcmlfbWVhbgoKYGBgCgoKIyMgU3RyZXNzIFJlbGF0ZWQgQWN0aXZpdHkKV2UgbmV4dCB0YWtlIGEgbG9vayBhdCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHN0cmVzcyBhbmQgY29udHJvbCBzZXNzaW9ucyBpbiB0aGUgTVJJLiBXZSBmaXJzdCBjb2RlIHRoZSBzdHJlc3MgYW5kIGNvbnRyb2wgc2Vzc2lvbiBhcyB3ZWxsIGFzIHRoZSBlYXJseSBhbmQgbGF0ZSBwaGFzZXMgdG8gbWFrZSBzb21lIGZhY3RvcnMgb3V0IG9mIHRoZW0uIFdlIGFsc28gZmlsdGVyIG9ubHkgdGhlIHNwZWNpZmljIGNvbnRyYXN0cyB3ZSB3YW50IHRvIGludmVzdGlnYXRlLiBUaGF0IGlzLCB0aGUgMkJhY2sgPiBub24tdGFyZ2V0LCB0aGUgb2RkYmFsbCA+IHN0YW5kYXJkLCBhbmQgdGhlIHJlbWVtYmVyZWQgPiBmb3Jnb3R0ZW4gY29udHJhc3RzLiBPbmNlIHdlIGhhdmUgdGhhdCwgd2UgY29uc3RydWN0IGEgZmlyc3QgbW9kZWwgdG8gbG9vayBhdCBtYWluIGVmZmVjdHMsIGFuZCB0aGVuIGJyZWFrICBkb3duIHRoZXNlIGVmZmVjdHMgcGVyIHRhc2svbmV0d29yay4gV2UgYWxzbyBjYW4gdGFrZSBhIGxvb2sgYXQgdGhlIGRpZmZlcmVuY2UgaW4gbmV1cmFsIHN0cmVzcyByZWFjdGl2aXR5LCBhbmQgaG93IHRoYXQgY2FuIGZ1cnRoZXIgaW5mb3JtIHVzIHJlZ2FyZGluZyBkYWlseSBsaWZlIHN0cmVzcyByZWFjdGl2aXR5LiBGaW5hbGx5IHdlIHRha2UgYSBsb29rIGF0IHRoZSBjb25jZXB0IG9mIG5ldHdvcmsgYmFsYW5jZSwgYXMgbGFpZCBvdXQgYnkgW0tyYXVzZSBldC4gYWwuIDIwMjFdKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzEwNTM4MTE5MjEwMDgwMDQ/dmlhJTNEaWh1YikuIAoKYGBge3J9CmRmX2Ztcmkuc3RyZXNzIDwtIGRmX2NvbWJvICU+JSBzZXBhcmF0ZShSdW4sIGludG89YygiU2Vzc2lvbiIsIlJ1biIpLCBzZXA9Ii0iICkgJT4lIHN1YnNldCgoY29wZT09ImNvcGUzIiAmIE5ldHdvcms9PSJFQ04iKSB8IChjb3BlPT0iY29wZTYiICYgTmV0d29yaz09IlNOIikgfCAoY29wZT09ImNvcGU5IiAmIE5ldHdvcms9PSJETU4iKSkgJT4lIGRwbHlyOjptdXRhdGUoTmV0d29yaz1yZWxldmVsKE5ldHdvcmssICJTTiIsICJFQ04iLCAiRE1OIikpCmBgYAoKIyMjIE1haW4gRWZmZWN0cyB7LSAudGFic2V0fQpJbiBvdXIgbWFpbiBtb2RlbCwgd2Ugc2VlIHRoYXQgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBzZXNzaW9uIGJ5IFJPSSBhbmQgc2Vzc2lvbiBieSBydW4gaW50ZXJhY3Rpb24gZWZmZWN0LiBUaGUgbWl4ZWQgbW9kZWxzIHNob3cgdXMgYSBjb21wYXJpc29uIHJlbGF0aXZlIHRvIGJhc2VsaW5lIGNvbmRpdGlvbnMgKENvbnRyb2wsIEVhcmx5KSBhbmQgaW4gbmV0d29yayAxIHdoaWNoIHdlIGNvZGVkIGFzIFNOLiBXZSBzZWUgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IG5ldHdvcmsgZWZmZWN0LCBzZXNzaW9uKnJ1biBpbnRlcmFjdGlvbiwgYW5kIHNlc3Npb24gYnkgbmV0d29yayBpbnRlcmFjdGlvbi4gV2UgYWxzbyBzZWUgdGhlcmUgaXMgYSBzaWduaWZpY2FudCA0LXdheSBpbnRlcmFjdGlvbiBlZmZlY3QgYmV0d2VlbiBzZXNzaW9uLCBydW4sIG5ldHdvcmssIGFuZCB0aGUgcmVzaWxpZW5jZSBzY29yZSBpbiB0aGUgRUNOIHJlbGF0aXZlIHRvIFNOLiBUbyBzaW1wbGlmeSB0aGUgaW50ZXJwcmV0YXRpb24sIHdlIGFsc28gcHJlc2VudCB0aGUgbW9kZWxzIGluIGEgc2ltcGxlIEFOT1ZBIG91dHB1dCBmb3IgZWFzaWVyIGludGVycHJldGF0aW9uIGZvciB0aGUgbW9kZWwgd2l0aCBvbmx5IHRoZSBTTiBhbmQgRUNOLiBUaGUgZXN0YWJsaXNobWVudCBvZiB0aGVzZSBtYWluIGVmZmVjdHMgYWxzbyBhbGxvd3MgdXMgdG8gcnVuIHRoZSBuZXh0IGZvbGxvdy11cCB0ZXN0cy4KCiMjIyMgTW9kZWw6IEZ1bGwgey19CmBgYHtyLCB3YXJuaW5nPUZBTFNFfQojIE1haW4gbW9kZWwgd2l0aG91dCBjb3Zhcml0YXRlcwptb2RlbC5mbXJpX21haW4gPC0gbG1lcihTaWduYWwgfiBTZXNzaW9uKlJ1bipOZXR3b3JrICsgZmlyc3Rfc2NhbiArIHNleCArICgxK1Nlc3Npb24rUnVuK05ldHdvcmt8aWQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KFNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX2Ztcmkuc3RyZXNzLCAKICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbD1sbWVyQ29udHJvbChvcHRpbWl6ZXI9ImJvYnlxYSIsIGNhbGMuZGVyaXZzID0gRikpCiMgUmVzaWRhbCBTY29yZSBNb2RlbAptb2RlbC5mbXJpX21haW5fcmVzIDwtIGxtZXIoU2lnbmFsIH4gU2Vzc2lvbipSdW4qTmV0d29yaypyZXNCSU4gKyBmaXJzdF9zY2FuICtzZXggKyAoMStTZXNzaW9uK1J1bitOZXR3b3JrfGlkKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChTZXNzaW9uPSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9mbXJpLnN0cmVzcywgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9bG1lckNvbnRyb2wob3B0aW1pemVyPSJib2J5cWEiLCBjYWxjLmRlcml2cyA9IEYpKQojIEFVQ2kgTW9kZWwKbW9kZWwuZm1yaV9tYWluX2F1Y2kgPC0gbG1lcihTaWduYWwgfiBTZXNzaW9uKlJ1bipOZXR3b3JrKkFVQ2lfZGlmZmVyZW5jZSArIGZpcnN0X3NjYW4gKyBzZXggKygxK1Nlc3Npb24rUnVuK05ldHdvcmt8aWQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChTZXNzaW9uPSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9mbXJpLnN0cmVzcywgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9bG1lckNvbnRyb2wob3B0aW1pemVyPSJib2J5cWEiLCBjYWxjLmRlcml2cyA9IEYpKQojIEZ1bGwgTW9kZWwKbW9kZWwuZm1yaV9tYWluX2Z1bGwgPC0gbG1lcihTaWduYWwgfiBTZXNzaW9uKlJ1bipOZXR3b3JrKnJlc0JJTiArIFNlc3Npb24qUnVuKk5ldHdvcmsqQVVDaV9kaWZmZXJlbmNlICsgZmlyc3Rfc2NhbiArIHNleCArICgxK1Nlc3Npb24rUnVuK05ldHdvcmt8aWQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChTZXNzaW9uPSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9mbXJpLnN0cmVzcywgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9bG1lckNvbnRyb2wob3B0aW1pemVyPSJib2J5cWEiLCBjYWxjLmRlcml2cyA9IEYpKQojIEhUTUwgVGFibGUgd2l0aCBhbGwKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVsLmZtcmlfbWFpbiwgIG1vZGVsLmZtcmlfbWFpbl9yZXMsIG1vZGVsLmZtcmlfbWFpbl9hdWNpLCAgbW9kZWwuZm1yaV9tYWluX2Z1bGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5zdGF0PVRSVUUsIHNob3cuc2U9VFJVRSwgZGlnaXRzID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHYubGFiZWxzID1jKCJTaWduYWwiLCAiU2lnbmFsflJlc2lsaWVuY2UiLCAiU2lnbmFsfkFVQ2kiLCAgIlNpZ25hbCB+RnVsbCIpKSRrbml0cikKCgpgYGAKCjxicj4KCiMjIyMgTW9kZWw6IEZ1bGwgYXMgQU5PVkEgey19CmBgYHtyfQphc2lzX291dHB1dChrYmwoYW5vdmEobW9kZWwuZm1yaV9tYWluKSwgZGlnaXRzPTMsIGNhcHRpb24gPSIqKkNsYXNzaWMgQU5PVkEgT3V0cHV0IG9mIE1haW4gRWZmZWN0KioiLCBhbGlnbiA9ImwiKSkKYGBgCgoKIyMjIyBQbG90IHstfQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBDYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBzdHJlc3MgYW5kIGNvbnRyb2wgCmRmX2Ztcmkuc3RyZXNzX3dpZGUgPC0gZGZfZm1yaS5zdHJlc3MgJT4lIHBpdm90X3dpZGVyKC4sIGlkX2NvbHMgPSBjKCJzdWJfbnIiLCJhZ2UiLCJzZXgiLCAiY29udHJhY2VwdGl2ZV91c2UiLCAiZmlyc3Rfc2NhbiIsICJOZXR3b3JrIiwiQ29udHJhc3QiKSwgbmFtZXNfZnJvbSA9YygiU2Vzc2lvbiIsIlJ1biIgKSwgdmFsdWVzX2Zyb209YygiU2lnbmFsIiwgInJlc0JJTiIsICJBVUNpX2RpZmZlcmVuY2UiKSkgJT4lIAogIG11dGF0ZShgU0UtQ0VgPVNpZ25hbF9TdHJlc3NfRWFybHktU2lnbmFsX0NvbnRyb2xfRWFybHksIGBTTC1DTGA9U2lnbmFsX1N0cmVzc19MYXRlLVNpZ25hbF9Db250cm9sX0xhdGUpICU+JQogIHBpdm90X2xvbmdlciguLCBjb2xzPWMoICJTRS1DRSIsICJTTC1DTCIpLCBuYW1lc190bz0iUnVuIix2YWx1ZXNfdG89IlN0cmVzcy1Db250cm9sIiApICU+JSAKICBkcGx5cjo6bXV0YXRlKFJ1bj1zdHJfcmVwbGFjZShSdW4sICJTRS1DRSIsICJFYXJseSIpLCBSdW49c3RyX3JlcGxhY2UoUnVuLCAiU0wtQ0wiLCAiTGF0ZSIpKQoKZGZfZm1yaS5zdHJlc3Mkc2V4IDwtIGFzLmZhY3RvcihkZl9mbXJpLnN0cmVzcyRzZXgpCmNvbnRyYXN0cyhkZl9mbXJpLnN0cmVzcyRzZXgpIDwtIGNvbnRyLnRyZWF0bWVudChjKCJNYWxlIiwgIkZlbWFsZSIpKQoKIyBNYWtlIHN1bW1hcnkgc3RhdHMKZGZfZm1yaS5zdHJlc3Nfc3VtbSA8LSBzdW1tYXJ5U0V3aXRoaW4oZGF0YT1kZl9mbXJpLnN0cmVzc193aWRlLCBpZHZhcj0ic3ViX25yIiwgbWVhc3VyZXZhcj0iU3RyZXNzLUNvbnRyb2wiLCB3aXRoaW52YXJzID0gYygiUnVuIiwgIk5ldHdvcmsiLCAiQ29udHJhc3QiKSkKZGZfZm1yaS5zdHJlc3Nfc3VtbSROZXRfUnVuIDwtcGFzdGUoZGZfZm1yaS5zdHJlc3Nfc3VtbSROZXR3b3JrLCBkZl9mbXJpLnN0cmVzc19zdW1tJFJ1biwgc2VwPSJcbiIpCmRmX2Ztcmkuc3RyZXNzX3N1bW0kTmV0X1J1biA8LSBmY3RfcmVsZXZlbChkZl9mbXJpLnN0cmVzc19zdW1tJE5ldF9SdW4sICJETU4tRWFybHkiLCAiRE1OLUxhdGUiLCAiRUNOLUVhcmx5IiwgIkVDTi1MYXRlIiwgIlNOLUVhcmx5IikKCiMgUGxvdApmbXJpX2NvbG9yczIgPC0gYygiIzAwQkZDNCIsIiMwMEI4RTciLCAiIzdDQUUwMCIsICIjMENCNzAyIiwgIiNGODc2NkQiLCIjRTY4NjEzIiApCnBsb3QuZm1yaV9zdHJlc3MgPC0gZ2dwbG90KGRmX2Ztcmkuc3RyZXNzX3N1bW0sIGFlcyh5PWBTdHJlc3MtQ29udHJvbGAsIHg9TmV0X1J1biwgY29sb3I9TmV0X1J1biwgZmlsbD1OZXRfUnVuLCBuYS5ybSA9IFRSVUUpKSArCiAgIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBjb2xvcj0iZ3JleSIpICsgCiAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgYWxwaGE9MC41LCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZTIoKSApICsKICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1gU3RyZXNzLUNvbnRyb2xgLXNlLCB5bWF4PWBTdHJlc3MtQ29udHJvbGArc2UpLHNpemU9MSwgbmEucm09VCx3aWR0aD0wLjQsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlMihwYWRkaW5nID0gMC43NSkpICsKICB5bGFiKHNwcmludGYoIlxVMDNCMlN0cmVzcyAtIFxVMDNCMiBDb250cm9sIChhLnUuKSIpKSArIHhsYWIoIk5ldHdvcmtzIikgKwogICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWZtcmlfY29sb3JzMikgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Zm1yaV9jb2xvcnMyKSArIAogICBnZ3RoZW1lMiArIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAsIHNpemU9MTYpLCBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEwKSwgYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTEyKSwKICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT0xMCksIGF4aXMudGlja3MueD1lbGVtZW50X2xpbmUoc2l6ZT0xKSwgYXhpcy50aXRsZS54ID1lbGVtZW50X3RleHQoc2l6ZT0xMikpIAogICNndWlkZXMoIGZpbGw9Im5vbmUiLGNvbG9yPWd1aWRlX2xlZ2VuZChjb2xvdXI9Zm1yaV9jb2xvcnMsIG92ZXJyaWRlLmFlcz1saXN0KGxpbmV0eXBlPWMoMSwgMSwgMSksIHNoYXBlPWMoMTYsMTYsMTYpLCBmaWxsPWMoIiMwMEJGQzQiLCIjMENCNzAyIiwiI0Y4NzY2RCIpICkpKSAKcGxvdC5mbXJpX3N0cmVzczsgZ2dzYXZlKCJmaWd1cmVzL0ZpZ3VyZV80X0Euc3ZnIiwgZGV2aWNlPSJzdmciLCBiZz0id2hpdGUiKQoKYGBgCgojIyMgTmV0d29yayBFZmZlY3RzIHstIC50YWJzZXR9CldlIGVzdGFibGlzaGVkIHNvbWUgaW50ZXJlc3Rpbmcgc3RyZXNzIGVmZmVjdHMgYWJvdmUuIE5vdyB3ZSB3YW50IHRvIHBlcmZvcm0gZm9sbG93LXVwIHRlc3RzIGZvciBlYWNoIG5ldHdvcmsgaW5kaXZpZHVhbGx5LiBOb3RlIHRoYXQgdGhlc2UgcmVzdWx0cyB0byBzb21lIGV4dGVudCAoZm9yIGV4YW1wbGUsIHNlc3Npb24gYW5kIHJ1biBlZmZlY3RzKSBhcmUganVzdCByZXBldGl0aW9ucyBvZiB0aGUgbWFpbiBlZmZlY3RzIHdlIGVzdGFibGlzaGVkIGFib3ZlLiBJbnRlcmVzdGluZ2x5LCB3ZSBzZWUgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGludGVyYWN0aW9uIGJldHdlZW4gc3RyZXNzLCB0aW1lLCBhbmQgdGhlIHJlc2lkdWFsIHJlc2lsaWVuY2Ugc2NvcmUgaW4gdGhlIHNhbGllbmNlIG5ldHdvcmsuIAoKIyMjIyBFQ04gey19CmBgYHtyfQojIEZpbHRlciBkZgpkZl9mbXJpLmVjbiA8LSBkZl9mbXJpLnN0cmVzcyAlPiUgc3Vic2V0KENvbnRyYXN0PT0iMkJhY2s+Tm9CYWNrIiAmIE5ldHdvcms9PSJFQ04iICkKCiMgUnVuIG1vZGVsIHdpdGggQVVDSQptb2RlbC5lY25fYXVjIDwtIGxtZXIoU2lnbmFsIH4gU2Vzc2lvbipSdW4qQVVDaV9kaWZmX3ogKyBmaXJzdF9zY2FuICsgc2V4ICsgKDErU2Vzc2lvbitSdW58c3ViX25yKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KFNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9mbXJpLmVjbiwgCiAgICAgICAgICAgICAgICAgICAgICBjb250cm9sPWxtZXJDb250cm9sKG9wdGltaXplcj1jKCJib2J5cWEiKSwgY2FsYy5kZXJpdnM9RikpCiMgUnVuIG1vZGVsIHdpdGggcmVzaWxpZW5jZQptb2RlbC5lY25fcmVzIDwtIGxtZXIoU2lnbmFsIH4gU2Vzc2lvbipSdW4qcmVzQklOICsgZmlyc3Rfc2NhbiArIHNleCArICgxK1Nlc3Npb24rUnVufHN1Yl9uciksCiAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChTZXNzaW9uPSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfZm1yaS5lY24sIAogICAgICAgICAgICAgICAgICAgICAgY29udHJvbD1sbWVyQ29udHJvbChvcHRpbWl6ZXI9YygiYm9ieXFhIiksIGNhbGMuZGVyaXZzPUYpKQojIEZ1bGwgbW9kZWwKbW9kZWwuZWNuX2Z1bGwgPC0gbG1lcihTaWduYWwgfiBTZXNzaW9uKlJ1bipyZXNCSU4gKyBTZXNzaW9uKlJ1bipBVUNpX2RpZmZfeiArIGZpcnN0X3NjYW4gKyBzZXggKyAoMStTZXNzaW9uK1J1bnxzdWJfbnIpLAogICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KFNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9mbXJpLmVjbiwKICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9bG1lckNvbnRyb2wob3B0aW1pemVyPWMoImJvYnlxYSIpLCBjYWxjLmRlcml2cz1GKSkKIyBUYWIgYW5kIHByaW50IHJlc3VsdHMKdGFiLmVjbl9yZWFjdCA8LSB0YWJfbW9kZWwobW9kZWwuZWNuX2F1YywgbW9kZWwuZWNuX3JlcywgbW9kZWwuZWNuX2Z1bGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGR2LmxhYmVscz1jKCJBVUNpIiwgIlJlYWwgTGlmZSIsICJGdWxsIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93LnNlID0gVCwgc2hvdy5zdGF0ID0gVCwgZW1waC5wID0gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGYubWV0aG9kPSJrZW53YXJkIiApCmtuaXRyOjphc2lzX291dHB1dCh0YWIuZWNuX3JlYWN0JGtuaXRyKQpgYGAKCgojIyMjIFNOIHstIC50YWJzZXR9CmBgYHtyfQojIEZpbHRlciBvbmx5IFNOCmRmX2Ztcmkuc24gPC0gZGZfZm1yaS5zdHJlc3MgJT4lIHN1YnNldChDb250cmFzdD09Ik9kZD5Ob2RkIiAmIE5ldHdvcms9PSJTTiIgKQojIEFVQyBtb2RlbAptb2RlbC5zbl9hdWMgPC0gbG1lcihTaWduYWwgfiBTZXNzaW9uKlJ1bipBVUNpX2RpZmZfeiArIGZpcnN0X3NjYW4gKyBzZXggKyAoMStTZXNzaW9uK1J1bnxzdWJfbnIpLAogICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChTZXNzaW9uPSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9mbXJpLnNuKQojIFJlc2lsaWVuY2UgTW9kZWwKbW9kZWwuc25fcmVzIDwtIGxtZXIoU2lnbmFsIH4gU2Vzc2lvbipSdW4qcmVzQklOICsgZmlyc3Rfc2NhbiArIHNleCArICgxK1Nlc3Npb24rUnVufHN1Yl9uciksCiAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KFNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX2Ztcmkuc24pCiMgRnVsbAptb2RlbC5zbl9mdWxsIDwtIGxtZXIoU2lnbmFsIH4gU2Vzc2lvbipSdW4qcmVzQklOICsgU2Vzc2lvbipSdW4qQVVDaV9kaWZmX3ogKyBmaXJzdF9zY2FuICsgc2V4ICsgKDErU2Vzc2lvbitSdW58c3ViX25yKSwKICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KFNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX2Ztcmkuc24pCiMgSFRNTCBUYWIKdGFiLnNuX3JlYWN0IDwtIHRhYl9tb2RlbChtb2RlbC5zbl9hdWMsIG1vZGVsLnNuX3JlcywgbW9kZWwuc25fZnVsbCwKICAgICAgICAgICAgICAgICAgICAgICAgICBkdi5sYWJlbHM9YygiQVVDaSIsICJSZWFsIExpZmUiLCAiRnVsbCIpLCBzaG93LnNlID0gVCwgc2hvdy5zdGF0ID0gVCkKa25pdHI6OmFzaXNfb3V0cHV0KHRhYi5zbl9yZWFjdCRrbml0cikKYGBgCgoKYGBge3J9CmVtdHJlbmRzKG1vZGVsLnNuX2Z1bGwsIGlkZW50aXR5IH4gU2Vzc2lvbiB8IFJ1biwgdmFyPSJyZXNCSU4iKQpgYGAKCgojIyMjIERNTiB7LX0KYGBge3J9CiMgRmlsdGVyIERNTiB0YXNrcwpkZl9mbXJpLmRtbiA8LSBkZl9mbXJpLnN0cmVzcyAlPiUgc3Vic2V0KENvbnRyYXN0PT0iUmVtPkZvciIgJiBOZXR3b3JrPT0iRE1OIiApCiMgQVVDIE1vZGVsCm1vZGVsLmRtbl9hdWMgPC0gbG1lcihTaWduYWwgfiBTZXNzaW9uKlJ1bipBVUNpX2RpZmZfeiArIGZpcnN0X3NjYW4gKyBzZXggKyAoMStTZXNzaW9uK1J1bnxzdWJfbnIpLAogICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3QoU2Vzc2lvbj0iY29udHIudHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX2ZtcmkuZG1uKQojIFJlc2lsaWVuY2UgTW9kZWwKbW9kZWwuZG1uX3JlcyA8LSBsbWVyKFNpZ25hbCB+IFNlc3Npb24qUnVuKnJlc0JJTiArIGZpcnN0X3NjYW4gKyBzZXggKyAoMStTZXNzaW9uK1J1bnxzdWJfbnIpLAogICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3QoU2Vzc2lvbj0iY29udHIudHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX2ZtcmkuZG1uKQojIEZ1bGwgbW9kZWwKbW9kZWwuZG1uX2Z1bGwgPC0gbG1lcihTaWduYWwgfiBTZXNzaW9uKlJ1bipyZXNCSU4gKyBTZXNzaW9uKlJ1bipBVUNpX2RpZmZfeiArIGZpcnN0X3NjYW4gKyBzZXggKyAoMStTZXNzaW9uK1J1bnxzdWJfbnIpLAogICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KFNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9bG1lckNvbnRyb2wob3B0aW1pemVyPSJib2J5cWEiLCBjYWxjLmRlcml2cyA9IEYpLAogICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9mbXJpLmRtbikKIyBIVE1MIE91dHB1dAp0YWIuZG1uX3JlYWN0IDwtIHRhYl9tb2RlbChtb2RlbC5kbW5fYXVjLCBtb2RlbC5kbW5fcmVzLCBtb2RlbC5kbW5fZnVsbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGR2LmxhYmVscz1jKCJBVUNpIiwgIlJlYWwgTGlmZSIsICJGdWxsIiksc2hvdy5zZT1ULCBzaG93LmVzdD1ULCBzaG93LnN0YXQgPSBUKQprbml0cjo6YXNpc19vdXRwdXQodGFiLmRtbl9yZWFjdCRrbml0cikKYGBgCgojIyMgU04gUmVhY3Rpdml0eSB7LSAudGFic2V0fQpXZSBzYXcgdGhlIG1haW4gZWZmZWN0cyBhYm92ZSwgbm93IHdlIHdhbnQgdG8gbG9vayBhcyBzcGVjaWZpYyBmb2xsb3ctdXBzIG9mIHRoZSBzdHJlc3MgcmVzaWxpZW5jZSBzY29yZXMgYW5kIHRoZSBjaGFuZ2VzIGluIE1SSSBzdHJlc3MgYWN0aXZpdHkgaW4gb3VyIG5ldHdvcmtzIG92ZXIgdGltZS4gV2Ugd2lsbCBvbmx5IGRvIHRoaXMgZm9yIHRoZSBTTiwgc2luY2UgdGhhdCBpcyB0aGUgb25seSBvbmUgb2Ygb3VyIG1haW4gdGVzdHMgd2hlcmUgd2Ugc2VlIGFuIGVmZmVjdCBvZiBzdHJlc3Mgb24gdGhlIG5ldHdvcmssIGFuZCBhbiBpbnRlcmFjdGlvbiBlZmZlY3Qgd2l0aCB0aGUgcmVzaWR1YWxpemVkIHNjb3JlLiBUbyB0aGlzIGVuZCwgd2Ugc3VidHJhY3QgU3RyZXNzLUNvbnRyb2wgZnJvbSB0aGUgTVJJIHNlc3Npb25zIHRvIGdldCBhIHNpbmdsZSBtZWFzdXJlIG9mIHdpdGhpbiBzdWJqZWN0IHJlYWN0aXZpdHkgaW4gdGhlIGxhYiBpbiB0aGUgZWFybHkgTVJJIHJ1biwgYW5kIHJlY292ZXIgaW4gdGhlIGxhdGUgTVJJIHJ1bi4KCkFkZGl0aW9uYWxseSwgaW4gdGhlc2UgbW9kZWxzIHdlIHNsaWdodGx5IGNoYW5nZSB0aGUgY29udHJhc3RzIHRvIHNlZSBzcGVjaWZpYyBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBlYXJseSBhbmQgbGF0ZSBwaGFzZXMuIFdlIHRoZXJlZm9yZSBjb2RlIHRoZSBlZmZlY3Qgb2YgUnVuIGFzIGEgY29udHJhc3QgdHJlYXRtZW50IGhlcmUuCmBgYHtyfQpkZl9mbXJpLnN0cmVzc193aWRlIDwtIGRmX2Ztcmkuc3RyZXNzICU+JSAgcGl2b3Rfd2lkZXIoaWRfY29scz1jKCJpZCIsImFnZSIsInNleCIsImNvbnRyYWNlcHRpdmVfdXNlIiwgIlJ1biIsICJOZXR3b3JrIiwgImZpcnN0X3NjYW4iKSwgbmFtZXNfZnJvbT0iU2Vzc2lvbiIsICB2YWx1ZXNfZnJvbT1jKCJTaWduYWwiLCAicmVzQklOIiwgIkFVQ2lfZGlmZmVyZW5jZSIpKSAlPiUgIGRwbHlyOjptdXRhdGUoU2lnbmFsPVNpZ25hbF9TdHJlc3MtU2lnbmFsX0NvbnRyb2wpICU+JSBkcGx5cjo6cmVuYW1lKHJlc0JJTj1yZXNCSU5fQ29udHJvbCkKYGBgCgoKIyMjIyBNYWluIE1vZGVsIHstfQpgYGB7cn0KZGZfZm1yaS5zdHJlc3Nfc24gPC0gZGZfZm1yaS5zdHJlc3Nfd2lkZSAlPiUgZHBseXI6OmZpbHRlcihOZXR3b3JrPT0iU04iKQptb2RlbC5zbl9ydW4gPC0gbG1lcihTaWduYWwgfiBSdW4qcmVzQklOICsgKDF8aWQpLCAgZGF0YT1kZl9mbXJpLnN0cmVzc19zbiwgY29udHJhc3RzPWxpc3QoUnVuPSJjb250ci50cmVhdG1lbnQiKSkKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVsLnNuX3J1biwgc2hvdy5zZT1ULCBzaG93LnN0YXQ9VFJVRSkka25pdHIpCmBgYAo8YnI+CgojIyMjIFBvc3QtSG9jIHstIC50YWJzZXR9CmBgYHtyfQpkZl9mbXJpLnN0cmVzc19zbl9lYXJseSA8LSBkZl9mbXJpLnN0cmVzc19zbiAlPiUgZmlsdGVyKFJ1bj09IkVhcmx5IikKbW9kZWwuc25fcnVuX2Vhcmx5IDwtIGxtKFNpZ25hbCB+IHJlc0JJTiwgZGF0YT1kZl9mbXJpLnN0cmVzc19zbl9lYXJseSkKZGZfZm1yaS5zdHJlc3Nfc25fbGF0ZSA8LSBkZl9mbXJpLnN0cmVzc19zbiAlPiUgZmlsdGVyKFJ1bj09IkxhdGUiKQptb2RlbC5zbl9ydW5fbGF0ZSA8LSBsbShTaWduYWwgfiAgcmVzQklOLCBkYXRhPWRmX2Ztcmkuc3RyZXNzX3NuX2xhdGUpCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtb2RlbC5zbl9ydW5fZWFybHksIG1vZGVsLnNuX3J1bl9sYXRlLCBkdi5sYWJlbHMgPSBjKCJFYXJseSIsICJMYXRlIiksIHNob3cuc3RhdD1UUlVFLCBzaG93LnNlPVQpJGtuaXRyKQplbW1pcChtb2RlbC5zbl9ydW4sIFJ1biB+IHJlc0JJTiwgY292LnJlZHVjZT1yYW5nZSkgKyBnZ3RoZW1lMgpgYGAKCgoKPGJyPgoKIyMjIyBQbG90OiBFYXJseSBTTi1SZXNpbGllbmNlIHstfQpgYGB7cn0KIyBQbG90IHRoZSBTTi1TdHJlc3MgcmVsYWl0b24gdG8gUmVzaWxpZW5jZQpkZl9mbXJpLnNuX2Vhcmx5X3dpZGUgPC0gZGZfZm1yaS5zbiAlPiUgZHBseXI6OmZpbHRlcihSdW49PSJFYXJseSIpICU+JSBwaXZvdF93aWRlcihpZF9jb2xzPWMoImlkIiwgImFnZSIsICJzZXgiLCAiY29udHJhY2VwdGl2ZV91c2UiLCAiZmlyc3Rfc2NhbiIpLCBuYW1lc19mcm9tPSJTZXNzaW9uIiwgIHZhbHVlc19mcm9tPWMoInJlc0JJTiIsICJTaWduYWwiKSkgJT4lICBkcGx5cjo6bXV0YXRlKFNpZ25hbD1TaWduYWxfU3RyZXNzLVNpZ25hbF9Db250cm9sKSAlPiUgZHBseXI6OnJlbmFtZShyZXNCSU49cmVzQklOX0NvbnRyb2wpICU+JSBkcGx5cjo6bXV0YXRlKHJlc0JJTj1yZXNCSU4qLTEpCgojIFBsb3QgMTogUmVzaWxpZW5jZSBieSByZWFjdGl2aXR5CnBsb3QuZm1yaV9zbmRpZmYgPSBnZ3Bsb3QoZGZfZm1yaS5zbl9lYXJseV93aWRlLCBhZXMoeD1yZXNCSU4sIHk9U2lnbmFsLCBjb2xvcj0iU3RyZXNzLUNvbnRyb2wiKSkgKyAKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIixmb3JtdWxhPXl+eCwgc2U9RiwgY29sb3I9IiNGODc2NkQiICkgKwogIGdlb21fcG9pbnQoYWxwaGE9MC43LCBjb2xvcj0iI0Y4NzY2RCIgKSArIAogIHhsYWIoc3ByaW50ZigiU04gRWFybHkgKFxVMDNCMiBTdHJlc3MgLSBcVTAzQjIgQ29udHJvbClcbiIpKSArIHlsYWIoIlJlYWwgTGlmZSBTdHJlc3NvciBSZWFjdGl2aXR5IChhLnUuKSIpICsKICBnZ3RoZW1lMiArIHRoZW1lKCAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTApLCBheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEwKSwgYXhpcy50aWNrcy54PWVsZW1lbnRfbGluZShzaXplPTEpLCBheGlzLnRpdGxlLnggPWVsZW1lbnRfdGV4dChzaXplPTEyKSkKcGxvdC5mbXJpX3NuZGlmZgpnZ3NhdmUoImZpZ3VyZXMvRmlndXJlXzRfQl9TTi5zdmciLCBkZXZpY2U9InN2ZyIsIGJnPSJ3aGl0ZSIpCmBgYAoKPGJyPgoKIyMjIyBQb3N0LUhvYzogUmVjb3Zlcnkgey19CgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgU3Vic2V0IHRoZSBkYXRhIHRvIGdldCBlYXJseS1sYXRlIGRpZmZlcmVuY2UKZGZfZm1yaS5zbl93aWRlX3JlY292ZXIgPC0gZGZfZm1yaS5zbiAlPiUgIHBpdm90X3dpZGVyKGlkX2NvbHM9YygiaWQiLCAiYWdlIiwgInNleCIsICJjb250cmFjZXB0aXZlX3VzZSIsICJmaXJzdF9zY2FuIiksIG5hbWVzX2Zyb209YygiU2Vzc2lvbiIsIlJ1biIpLCAgdmFsdWVzX2Zyb209YygicmVzQklOIiwgIlNpZ25hbCIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShTaWduYWxfTGF0ZT1TaWduYWxfU3RyZXNzX0xhdGUtU2lnbmFsX0NvbnRyb2xfTGF0ZSwgU2lnbmFsX0Vhcmx5PVNpZ25hbF9TdHJlc3NfRWFybHktU2lnbmFsX0NvbnRyb2xfRWFybHksIFNpZ25hbD1TaWduYWxfTGF0ZS1TaWduYWxfRWFybHkpICU+JQogIGRwbHlyOjpyZW5hbWUocmVzQklOPXJlc0JJTl9TdHJlc3NfRWFybHkpIAoKIyBSZW1vdmUgb3V0bGllcnMKc2lnbmFsX3NkIDwtIHNkKGRmX2Ztcmkuc25fd2lkZV9yZWNvdmVyJFNpZ25hbCozKQpzaWduYWxfc2RfbmVnIDwtIC1zaWduYWxfc2QKZGZfZm1yaS5zbl93aWRlX3JlY292ZXIgPC0gZGZfZm1yaS5zbl93aWRlX3JlY292ZXIgJT4lIG11dGF0ZShTaWduYWw9cmVwbGFjZShTaWduYWwsIFNpZ25hbDxzaWduYWxfc2RfbmVnIHwgU2lnbmFsPnNpZ25hbF9zZCwgTkEpKQoKIyBNb2RlbAphc2lzX291dHB1dCh0YWJfbW9kZWwobG0oU2lnbmFsIH4gcmVzQklOLCBkYXRhPWRmX2Ztcmkuc25fd2lkZV9yZWNvdmVyKSwgdGl0bGU9IkNoYW5nZSBmcm9tIEVhcmx5IHRvIExhdGUiKSRrbml0cikKCmBgYApgCgoKIyMjIEZ1bGwgTVJJIFN0cmVzcyBQbG90IHstfQpgYGB7cn0KZ2dhcnJhbmdlKHBsb3QuZm1yaV9zdHJlc3MsIE5VTEwsIHBsb3QuZm1yaV9zbmRpZmYsIHdpZHRocz1jKDEuMiwwLjAxLCAxKSwgbmNvbCA9IDMsIGxhYmVscyA9IGMoIkEiLCAiQiIpLCBhbGlnbiA9ICJodiIpCmdnc2F2ZSgiZmlndXJlcy9GaWd1cmVfNF9mTVJJU3RyZXNzLnN2ZyIsIGRldmljZT0ic3ZnIikKYGBgCgoKIyBmTVJJOiBUYXNrcwpXZSBoYXZlIHRocmVlIHRhc2tzIGR1cmluZyB0aGUgZk1SSSBzZXNzaW9uIHdoaWNoIHdlIG5lZWQgdG8gYW5hbHl6ZSBmb3Igb3VyIHN0dWR5IGFzIG1lbnRpb25lZCBpbiB0aGUgW0ludHJvZHVjdGlvbl0oKSBzZWN0aW9uLiBUaGVzZSB0YXNrcyBpbmNsdWRlIGEgMi1CYWNrLCBPZGRiYWxsLCBhbmQgQXNzb2NpYXRpdmUgUmV0cmlldmFsLiBFYWNoIHJlcXVpcmVzIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGFwcHJvYWNoIHNvIHdlIGRvIHNvbWUgZGF0YSBjbGVhbmluZyBpbiBjaHVua3Mgb2YgY29kZSBiZWZvcmUgd2Ugc3RhcnQuIAoKIyMgRGF0YSBDbGVhbmluZwpXZSBmaXJzdCBpbXBvcnQgdGhlIGRhdGEgZnJvbSBpbmRpdmlkdWFsIGxvZ3MuIFRvIHRoaXMgZW5kLCB3ZSBoYXZlIGEgc21hbGwgZnVuY3Rpb24gdGhhdCByZWFkcyBhIGZpbGUgYW5kIGFzc2lnbnMgdGhlIHN1YmplY3QgSUQuIFdlIGNvbXBpbGUgdGhlIHRyaWFsLWJ5LXRyaWFsIGxvZ3MgZm9yIGFsbCBzdWJqZWN0cyBpbnRvIGEgc2luZ2xlIGRhdGEgZnJhbWUgd2hpY2ggd2UgdGhlbiBzdWJzZXQgZm9yIGVhY2ggdGFzayBzZXBhcmF0ZWx5LiBXZSB0aGVuIGNvbWJpbmUgdGhpcyBkYXRhIGZyYW1lIHdpdGggdGhlIGxhc3QgZGF0YSBmcmFtZSB3ZSB1c2VkIGluIHRoZSBwcmV2aW91cyBzZWN0aW9uIGZvciB0aGUgYmFsYW5jZS4gCmBgYHtyfQojIEZpcnN0IGdldCBhIGxpc3Qgb2YgYWxsIHRoZSBsb2cgZmlsZXMKbG9nc19iZWggPC0oU3lzLmdsb2IoIi9wcm9qZWN0LzMwMTMwNjguMDIvZGF0YS8qL2xvZ3MvbXJpLyptcmkqIikpCiMgTWFrZSBhIGZ1bmN0aW9uIHRvIHJlYWQgdGhlIGxvZyBmaWxlcyArIGFkZCBzZXNzaW9uICsgc3ViamVjdCBpbmZvCnJlYWRfYWRkIDwtIGZ1bmN0aW9uKGZpbGUsIHNlcGVyYXRvciwgaGVhZGVycyl7CiAgICBkZiA8LSByZWFkLmNzdjIoZmlsZT1maWxlLCBzZXA9c2VwZXJhdG9yLCBoZWFkZXI9aGVhZGVycykKICAgIGlkIDwtIGZpbGU7IGlkIDwtIHN1YigiLipzdWJfIiwgIiIsIGlkKTsgaWQgPC0gc3ViKCIvbG9ncy8uKiIsICIiLCBpZCkKICAgIGRmJGlkIDwtIGlkCiAgICAjIFNlbGVjdCBzZXNzaW9uIGluZGljYXRpb3IKICAgIHNlcyA8LSBmaWxlOyBzZXMgPC0gc3ViKCIuKmxvZ3MvbXJpL1N1YiIsICIiLCBzZXMpOyBzZXMgPC0gc3ViKCIudHh0LioiLCAiIiwgc2VzKQogICAgZGYkc2VzIDwtIHNlcwogICAgZGYgfQoKIyBSdW4gZnVuY3Rpb24KZGZfdGFzayA8LSByYmluZGxpc3QobGFwcGx5KGxvZ3NfYmVoLCByZWFkX2FkZCwgc2VwZXJhdG9yPSJcdCIsIGhlYWRlcnM9RkFMU0UpKQojIENvbG91bW4gaGVhZGVycwpuYW1lcyhkZl90YXNrKSA8LSBjKCJ0YXNrIiwgInN0aW11bHVzIiwgInZhbGVuY2UiLCAidHJpYWxfb25zZXQiLCAidHJpYWxfb2Zmc2V0IiwgInJ0IiwgImJ1dHRvbl9wcmVzc2VkIiwgImJ1dHRvbl9jb3JyZWN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICJibG9ja19vbnNldCIsImJsb2NrX29mZnNldCIsImV4cGVyaW1lbnRfc3RhcnQiLCAiZXhwZXJpbWVudF9lbmQiLCAic3ViX2lkIiwgInNlc3Npb25faWQiKQojIERyb3AgdGhlIGhlYWRlcnMgYWRkZWQgd2hlbiBpbXBvcnRpbmcsIGFuZCByZXR5cGUKZGZfdGFzayA8LSBkZl90YXNrICU+JSBzdWJzZXQodGFzayAhPSAiVHJpYWxfVHlwZSIgJiB0YXNrICE9ICJUcmlhbF9UeXBlICIgKSAlPiUgc2VwYXJhdGUoc2Vzc2lvbl9pZCwgYygic3ViIiwgIm1yaSIsICJzZXNzaW9uIiwicnVuIikpICAlPiUgcmV0eXBlKCkKCiMgTWFrZSBhIGZhY3RvciBmb3IgdGFzayB0eXBlcyBhbmQgc2Vzc2lvbnMgYW5kIHJ1bnMKZGZfdGFzayRzdWJfaWQgPC0gYXMuZmFjdG9yKGRmX3Rhc2skc3ViX2lkKQpkZl90YXNrJHN1Yl9uciA8LSBwYXN0ZSgic3ViIiwgKHN0cl9wYWQoZGZfdGFzayRzdWJfaWQsIDMsIHBhZCA9ICIwIikpLCBzZXA9Il8iKSAKIyBMYWJlbCB0aGUgdGFza3MKZGZfdGFzayRUYXNrIDwtIGZhY3RvcihkZl90YXNrJHRhc2ssIGxldmVsPWMoMSwyLDMpLCBsYWJlbHM9Yygib2RkYmFsbCIsICJuYmFjayIsICJtZW1vcnkiKSkKIyBMYWJlbCB0aGUgc2Vzc2lvbiBhbmQgcnVucwpkZl90YXNrJFNlc3Npb24gPC0gZmFjdG9yKGRmX3Rhc2skc2Vzc2lvbiwgbGV2ZWw9YygiczEiLCJzMiIpLCBsYWJlbHM9YygiQ29udHJvbCIsICJTdHJlc3MiKSkKZGZfdGFzayRSdW4gPC0gZmFjdG9yKGRmX3Rhc2skcnVuLCBsZXZlbD1jKCJyMSIsInIyIiwicjMiLCJyNCIsInI1IiwicjYiKSwgbGFiZWxzPWMoInIxIiwicjIiLCJyMyIsInI0IiwicjUiLCJyNiIpKQpkZl90YXNrJHJ1biA8LSBhcy5udW1lcmljKGRmX3Rhc2skUnVuKQpkZl90YXNrJFBoYXNlIDwtICJMYXRlIgpkZl90YXNrJFBoYXNlW2RmX3Rhc2skUnVuID09InIxIiB8IGRmX3Rhc2skUnVuID09InIyIiB8IGRmX3Rhc2skUnVuID09InIzIl0gPC0gIkVhcmx5IgpkZl90YXNrJHJ1biA8LSBhcy5udW1lcmljKGRmX3Rhc2skUnVuKQoKIyBTdWJzZXQgdGhlIGZtcmkgZGF0YWZyYW1lCmRmX2ZtcmkuYmFsYW5jZV80dGFza3MgPC0gZGZfZm1yaS5zdHJlc3MgICU+JSAgcGl2b3Rfd2lkZXIoaWRfY29scz1jKGlkLCBhZ2UsIHNleCwgY29udHJhY2VwdGl2ZV91c2UsIGZpcnN0X3NjYW4sIFNlc3Npb24sIFJ1biksIG5hbWVzX2Zyb209YyhOZXR3b3JrKSwgdmFsdWVzX2Zyb209YyhTaWduYWwscmVzQklOLEFVQ2lfZGlmZmVyZW5jZSkgKSAlPiUgZHBseXI6OnNlbGVjdCgxOjExLDE1KSAKbmFtZXMoZGZfZm1yaS5iYWxhbmNlXzR0YXNrcyApIDwtIGMoInN1Yl9uciIsImFnZSIsInNleCIsICJjb250cmFjZXB0aXZlX3VzZSIsICJTY2FuX09yZGVyIiwgICJTZXNzaW9uIiwgIlJ1biIsICJFQ04iLCAiU04iLCAiRE1OIiwgInJlc0JJTiIsICJBVUNpX2RpZmYiKQojIE1ha2UgdGhlIHNjb3JlcwpkZl9mbXJpLmJhbGFuY2VfNHRhc2tzICA8LSBkZl9mbXJpLmJhbGFuY2VfNHRhc2tzICAlPiUgZHBseXI6Om11dGF0ZShTTl9FQ049U04tRUNOLCBFQ05fRE1OPUVDTi1ETU4sIFNOX0RNTj1TTi1ETU4pICU+JSBkcGx5cjo6ZmlsdGVyKCFpcy5uYShzZXgpKQoKZGZfdGFzayA8LSBtZXJnZShkZl90YXNrLCBkZl9mbXJpLmJhbGFuY2VfNHRhc2tzLCBieS54PWMoInN1Yl9uciIsICJTZXNzaW9uIiwgIlBoYXNlIiksIGJ5Lnk9Yygic3ViX25yIiwgIlNlc3Npb24iLCAiUnVuIikpCmBgYAoKIyMjIE5iYWNrIHstfQpXZSBzdGFydCBvZiB3aXRoIHRoZSBuYmFjayB0YXNrLiBXZSBmaXJzdCBjb3JyZWN0IHRoZSBuYmFjayB0cmlhbHMgZm9yIHRoZSBiYXNlbGluZSByZWFjdGlvbiBzcGVlZCB1c2luZyB0aGUgb2RkYmFsbCByZWFjdGlvbiB0aW1lIGZyb20gZWFjaCBydW4gYXMgdGhlIGNvcnJlY3RpbmcgZmFjdG9yLiBXZSB0aGVuIGFsc28gY2FsY3VsYXRlIGEgbWVhc3VyZSB0aGF0IGNvbWJpbmVzIHNwZWVkIGFuZCBhY2N1cmFjeSBhZnRlciB0aGF0LiBIZXJlIHdlIHVzZSB0aGUgTElBU0VTIG1ldGhvZCwgd2hpY2ggaXMgYSBiaXQgY29tcGxpY2F0ZWQuIFdlIGRvIHRoaXMgaW4gYSBzZXBhcmF0ZSBjaHVuay4gCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRmX3Rhc2submJhY2sgPC0gZGZfdGFzayAlPiUgZ3JvdXBfYnkoc3ViX2lkLCBTZXNzaW9uLCBSdW4pICU+JSBkcGx5cjo6bXV0YXRlKG9kZF9tZWFuX3J0PW1lYW4oaWZlbHNlKFRhc2s9PSJvZGRiYWxsIiwgcnQsIE5BKSwgbmEucm09VFJVRSkpICU+JSB1bmdyb3VwKCkgJT4lIHN1YnNldChUYXNrPT0ibmJhY2siKSAlPiUgc3Vic2V0KHJ0PjIwMCkKZGZfdGFzay5uYmFjayRydF9jb3JyIDwtIGRmX3Rhc2submJhY2skcnQvZGZfdGFzay5uYmFjayRvZGRfbWVhbl9ydApkZl90YXNrLm5iYWNrJEhpdFtkZl90YXNrLm5iYWNrJGJ1dHRvbl9wcmVzc2VkPjAgJiBkZl90YXNrLm5iYWNrJGJ1dHRvbl9jb3JyZWN0PjBdIDwtIDEgCmRmX3Rhc2submJhY2skTWlzc1tkZl90YXNrLm5iYWNrJGJ1dHRvbl9wcmVzc2VkPT0wICYgZGZfdGFzay5uYmFjayRidXR0b25fY29ycmVjdD4wXSA8LSAxIApkZl90YXNrLm5iYWNrJEZBW2RmX3Rhc2submJhY2skYnV0dG9uX3ByZXNzZWQ+MCAmIGRmX3Rhc2submJhY2skYnV0dG9uX2NvcnJlY3Q9PTBdIDwtIDEgCmRmX3Rhc2submJhY2skQ29yclJlaltkZl90YXNrLm5iYWNrJGJ1dHRvbl9wcmVzc2VkPT0wICYgZGZfdGFzay5uYmFjayRidXR0b25fY29ycmVjdD09MF0gPC0gMSAKYGBgIAoKV2Ugbm93IGNhbGN1bGF0ZSB0aGUgTElBU0VTIHNjb3JlIGJhc2VkIGFzIGRldGFpbGVkIGluIHRoZSBtZXRob2RzIHBhcGVyIGJ5IFtBbmRyw6kgVmFuZGllcmVuZG9uY2sgKDIwMTcpXShodHRwczovL2xpbmsuc3ByaW5nZXIuY29tL2FydGljbGUvMTAuMzc1OC9zMTM0MjgtMDE2LTA3MjEtNSkuIFdlIG5lZWQgdG8gZ2V0IHRoZSBSVCBieSBwYXJ0aWNpcGFudC9jb25kaXRpb24sIHRoZSBTRCBvZiBib3RoIHRoZSBSVHMgYW5kIHRoZSBQRXMsIGFuZCB0aGVuIHRoZSB0b3RhbCBQRSBwZXIgY29uZGl0aW9uLiBTTyB3ZSBjYW4gdGhlbiBjb21wYXJlIHRoaXMgbWVhc3VyZSBiZXR3ZWVuIHJ1bnMgYW5kIGNvbmRpdGlvbnMuIFRoZSBmb3JtdWxhIGlzIFJUaisgKFNEKFJUKS9TRChQRSkpICogUEVqIHdoZXJlIGo9Y29uZGl0aW9uLiBTbyBJIGZpcnN0IGdyb3VwIGJ5IHN1YmplY3QsIGdldCB0aGUgUlQgc2QsIHRoZW4gZ3JvdXAgYnkgc2Vzc2lvbiBhbmQgcnVuIHRvIGdldCB0aGUgUEUgcGVyIGNvbmRpdGlvbiwgYW5kIHRoZSBSVCBwZXIgY29uZGl0aW9uLCBhbmQgZmluYWxseSBJIGdldCB0aGUgb3ZlcmFsbCBQRSBmcm9tIGFsbCBjb25kaXRpb25zLiAKYGBge3J9CmRmX3Rhc2submJhY2sgPC0gZGZfdGFzay5uYmFjayAlPiUgZ3JvdXBfYnkoc3ViX2lkKSAlPiUgZHBseXI6Om11dGF0ZShydF9zZD1zZChpZmVsc2UocnQhPTAsIHJ0LCBOQSksIG5hLnJtPVRSVUUpKSAlPiUgZ3JvdXBfYnkoc3ViX2lkLCBTZXNzaW9uLCBSdW4pICU+JSBkcGx5cjo6bXV0YXRlKHBlPSgoc3VtKEZBLCBuYS5ybT1UUlVFKSsgc3VtKE1pc3MsIG5hLnJtPVRSVUUpKS9sZW5ndGgocnQpKSwgcnRfbWVhbj1tZWFuKGlmZWxzZShydCE9MCwgcnQsIE5BKSwgbmEucm09VFJVRSkpICU+JSB1bmdyb3VwICU+JSBncm91cF9ieShzdWJfaWQpICU+JSBkcGx5cjo6bXV0YXRlKHBlX3NkPXNkKHBlLCBuYS5ybT1UUlVFKSkgJT4lIHN1YnNldChydD4yMDApICU+JSB1bmdyb3VwICU+JSBkcGx5cjo6bXV0YXRlKExJQVNFUz1ydF9tZWFuKyhydF9zZC9wZV9zZCkqcGUpICU+JSB1bmdyb3VwKCkKYGBgCgojIyMgTWVtb3J5IHstfQpGb3IgdGhlIG1lbW9yeSB0YXNrcywgd2UgaGF2ZSB0cmlhbHMgd2l0aCBuZWdhdGl2ZSwgYW5kIG90aGVycyB3aXRoIG5ldXRyYWwgaW1hZ2VzLiBTbyB0aGUgZ29hbCBpcyB0byBsb29rIGF0IFJUJ3MsIGFzIHdlbGwgYXMgdGhlIHBlcmNlbnQgb2YgY29ycmVjdCByZXNwb25zZXMuIFdlIHN1YnNldCB0aGUgbWVtb3J5IHRyaWFscyBmcm9tIHRoZSBtYWluIGRhdGEgZnJhbWUgaGVyZSwgYW5kIHRoZW4gY2FsY3VsYXRlIGFsbCB0aGUgbWVhc3VyZXMgd2UgbmVlZCBmb3IgYW5hbHlzaXMuIApgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIEZpbHRlciBvdXQgdGhlIG1lbW9yeSB0cmlhbHMKZGZfdGFzay5tZW0gPC0gZGZfdGFzayAlPiUgc3Vic2V0KFRhc2s9PSJtZW1vcnkiKQojIExhYmVsIHRoZSBmYWN0b3JzCmRmX3Rhc2subWVtJHZhbGVuY2UgPC0gZmFjdG9yKGRmX3Rhc2subWVtJHZhbGVuY2UsIGxldmVscz1jKDEsMiksIGxhYmVscz1jKCJuZXV0cmFsIiwibmVnYXRpdmUiKSkKIyBHZXQgdGhlIG51bWJlciBvZiBjb3JyZWN0IGFuc3dlcnMgYW5kIHZhbGVuY2VzIGZvciBzdW0gY2FsY3VsYXRlcwpkZl90YXNrLm1lbSRjb3JyX3Jlc3BbZGZfdGFzay5tZW0kYnV0dG9uX2NvcnJlY3Q9PWRmX3Rhc2subWVtJGJ1dHRvbl9wcmVzc2VkXSA8LSAxCmRmX3Rhc2subWVtJGluY29ycl9yZXNwW2RmX3Rhc2subWVtJGJ1dHRvbl9jb3JyZWN0IT1kZl90YXNrLm1lbSRidXR0b25fcHJlc3NlZF0gPC0gMQpkZl90YXNrLm1lbSRtZW1fbmV1X25bZGZfdGFzay5tZW0kdmFsZW5jZT09Im5ldXRyYWwiXSA8LSAxCmRmX3Rhc2subWVtJG1lbV9uZWdfbltkZl90YXNrLm1lbSR2YWxlbmNlPT0ibmVnYXRpdmUiXSA8LSAxCgojIEdldCBhdmVyYWdlcyBhbmQgdGhlIGxpa2VzCmRmX3Rhc2subWVtIDwtIGRmX3Rhc2subWVtICU+JSBncm91cF9ieShzdWJfaWQsIFNlc3Npb24sIFJ1bikgJT4lIGRwbHlyOjptdXRhdGUoCiAgICBtZW1fbmV1PXN1bShpZmVsc2UodmFsZW5jZT09Im5ldXRyYWwiLCBtZW1fbmV1X24sIE5BKSwgbmEucm09VFJVRSksCiAgICBtZW1fbmVnPXN1bShpZmVsc2UodmFsZW5jZT09Im5lZ2F0aXZlIiwgbWVtX25lZ19uLCBOQSksIG5hLnJtPVRSVUUpLCAKICAgIG1lbV90b3Q9bWVtX25lZyttZW1fbmV1LCAKICAgIG1lbV9uZXVfY29ycj1zdW0oaWZlbHNlKHZhbGVuY2U9PSJuZXV0cmFsIiwgY29ycl9yZXNwLCBOQSksIG5hLnJtPVRSVUUpLAogICAgbWVtX25lZ19jb3JyPXN1bShpZmVsc2UodmFsZW5jZSE9Im5ldXRyYWwiLCBjb3JyX3Jlc3AsIE5BKSwgbmEucm09VFJVRSksCiAgICBtZW1fdG90X2NvcnI9bWVtX25lZ19jb3JyK21lbV9uZXVfY29yciwgCiAgICBtZW1fbmVnX3Blcj1tZW1fbmVnX2NvcnIvbWVtX25lZywKICAgIG1lbV9uZXVfcGVyPW1lbV9uZXVfY29yci9tZW1fbmV1LCAKICAgIG1lbV90b3RfcGVyPShtZW1fbmV1X2NvcnIrbWVtX25lZ19jb3JyKS9tZW1fdG90KSAlPiUgdW5ncm91cApgYGAKCiMjIyBPZGRiYWxsIHstfQpXZSBhbHNvIG5lZWQgdG8gaW1wb3J0IHRoZSBkYXRhIGxvZ3MgZm9yIHRoZSBvZGRiYWxsLiBUaGUgbWFpbiBvdXRjb21lIG1lYXN1cmUgZm9yIHRoaXMgdGFzayBpcyB0aGUgb2RkYmFsbCByZWNhbGwgZG9uZSBvdXRzaWRlIHRoZSBzY2FubmVyLCB3aGljaCB3ZSBhbmFseXplIGEgbGl0dGxlIGRpZmZlcmVudGx5LiBGb3IgdGhpcywgd2UgbmVlZCB0byBjYWxjdWxhdGUgZHByaW1lLiBJIHdpbGwgYWxzbyBiZSBsb29raW5nIGF0IHRoZSBSVHMgaGVyZSBmb3IgdGhlIGluZGl2aWR1YWwgdHJpYWxzIGR1cmluZyBzY2FubmluZyBoZXJlLiBTbyBpbiBhZGRpdGlvbiB0byB0aGUgcHJldmlvdXMgZGF0YSBmcmFtZSBmcm9tIHRoZSBzY2FuLCB3ZSBhbHNvIGltcG9ydCB0aGUgZGF0YSBmcmFtZSBmcm9tIG91dHNpZGUgdGhlIHNjYW5uZXIuIFRoaXMgd2FzIGFscmVhZHkgZG9uZSBpbiBweXRob24sIHNvIHdlIGp1c3QgbmVlZCB0byBicmluZyBpbiB0aGUgbmV3IGRhdGEgZnJhbWUgd2l0aCBzb21lIG1pbm9yIGNsZWFuaW5nLiBXZSBhbHNvIGNhbGN1bGF0ZSBkcHJpbWUgZm9yIHRoZSBvdmVyYWxsIHBlcmZvcm1hbmNlLCBhbmQgYWxzbyB0aGUgcGVyZm9ybWFuY2UgYnkgdmFsZW5jZQpgYGB7cn0KIyBPZGRiYWxsIGRmCmRmX3Rhc2sub2RkICA8LSByZWFkLmNzdigiL3Byb2plY3QvMzAxMzA2OC4wMi9zdGF0cy9mTVJJL0JlaGF2aW9yYWwvZm1yaV9yZWNhbGwuY3N2Iiwgc2VwPSJcdCIsIGhlYWRlcj1UUlVFKQoKI0FkZCB2YXJpYWJsZSBmb3Igc2VwYXJhdGluZyBsYXRlLCBlYXJseSAKZGZfdGFzay5vZGQkU2NhbltkZl90YXNrLm9kZCRzZXNzaW9uPT0xICYgZGZfdGFzay5vZGQkcnVuPT0xXSA8LSAxCmRmX3Rhc2sub2RkJFNjYW5bZGZfdGFzay5vZGQkc2Vzc2lvbj09MSAmIGRmX3Rhc2sub2RkJHJ1bj09Ml0gPC0yCmRmX3Rhc2sub2RkJFNjYW5bZGZfdGFzay5vZGQkc2Vzc2lvbj09MiAmIGRmX3Rhc2sub2RkJHJ1bj09MV0gPC0zCmRmX3Rhc2sub2RkJFNjYW5bZGZfdGFzay5vZGQkc2Vzc2lvbj09MiAmIGRmX3Rhc2sub2RkJHJ1bj09Ml0gPC00CiNNYWtlIHBoYXNlcyBpbnRvIGZhY3RvcgpkZl90YXNrLm9kZCRTZXNzaW9uIDwtIGZhY3RvcihkZl90YXNrLm9kZCRzZXNzaW9uLCBsZXZlbHM9YygxLDIpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygnQ29udHJvbCcsICdTdHJlc3MnKSkKZGZfdGFzay5vZGQkU2NhbiA8LSBmYWN0b3IoZGZfdGFzay5vZGQkU2NhbiwgbGV2ZWxzPWMoMSwyLCAzLDQpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygnQ29udHJvbC1FYXJseScsJ0NvbnRyb2wtTGF0ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdTdHJlc3MtRWFybHknLCAnU3RyZXNzLUxhdGUnKSkKZGZfdGFzay5vZGQkUnVuIDwtIGZhY3RvcihkZl90YXNrLm9kZCRydW4sIGxldmVscz1jKDEsMiksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJFYXJseSIsIkxhdGUiKSkKCiMgQWRkIHRoZSBNUkkgc2lnbmFsIGRhdGEKZGZfdGFzay5vZGQgPC0gbWVyZ2UoZGZfdGFzay5vZGQsIGRmX2ZtcmkuYmFsYW5jZV80dGFza3MsIGJ5Lng9Yygic3ViX25yIiwgIlNlc3Npb24iLCAiUnVuIiksIGJ5Lnk9Yygic3ViX25yIiwgIlNlc3Npb24iLCAiUnVuIikpCgojIE5vdyB3ZSBjYWxjdWxhdGUgZHByaW1lCiMjRmlyc3QgSSBkcm9wIHRoZSBOQXMKZGZfdGFzay5vZGQgPC0gbmEub21pdChkZl90YXNrLm9kZCkKZGZfdGFzay5vZGRfdGVtcCA8LSBkZl90YXNrLm9kZAoKIyBUaGVuIG1ha2UgdGhlIGZyYW1lCmRmX3Rhc2sub2RkX2RwcmltZV9uZWcgPC1hcy5kYXRhLmZyYW1lKGRwcmltZShkZl90YXNrLm9kZF90ZW1wJG9kZF9oaXRzX25lZywgZGZfdGFzay5vZGRfdGVtcCRvZGRfRkFfbmVnLCBuX21pc3M9ZGZfdGFzay5vZGRfdGVtcCRvZGRfbWlzc19uZWcsIG5fY3I9ZGZfdGFzay5vZGRfdGVtcCRvZGRfY29ycmVqX25lZykpCmNvbG5hbWVzKGRmX3Rhc2sub2RkX2RwcmltZV9uZWcpIDwtIHBhc3RlKGNvbG5hbWVzKGRmX3Rhc2sub2RkX2RwcmltZV9uZWcpLCAibmVnIiwgc2VwID0gIl8iKQpkZl90YXNrLm9kZCA8LSBjYmluZChkZl90YXNrLm9kZCwgZGZfdGFzay5vZGRfZHByaW1lX25lZykKCmRmX3Rhc2sub2RkX2RwcmltZV9wb3MgPC0gYXMuZGF0YS5mcmFtZShkcHJpbWUoZGZfdGFzay5vZGRfdGVtcCRvZGRfaGl0c19wb3MsIGRmX3Rhc2sub2RkX3RlbXAkb2RkX0ZBX3Bvcywgbl9taXNzPWRmX3Rhc2sub2RkX3RlbXAkb2RkX21pc3NfcG9zLCBuX2NyPWRmX3Rhc2sub2RkX3RlbXAkb2RkX2NvcnJlal9wb3MpKQpjb2xuYW1lcyhkZl90YXNrLm9kZF9kcHJpbWVfcG9zKSA8LSBwYXN0ZShjb2xuYW1lcyhkZl90YXNrLm9kZF9kcHJpbWVfcG9zKSwgInBvcyIsIHNlcCA9ICJfIikKZGZfdGFzay5vZGQgPC0gY2JpbmQoZGZfdGFzay5vZGQsIGRmX3Rhc2sub2RkX2RwcmltZV9wb3MpCgpkZl90YXNrLm9kZF9kcHJpbWUgPC0gZHByaW1lKGRmX3Rhc2sub2RkX3RlbXAkb2RkX2hpdHMsIGRmX3Rhc2sub2RkX3RlbXAkb2RkX0ZBLCBuX21pc3M9ZGZfdGFzay5vZGRfdGVtcCRvZGRfbWlzcywgbl9jcj1kZl90YXNrLm9kZF90ZW1wJG9kZF9jb3JyZWopCmRmX3Rhc2sub2RkIDwtIGNiaW5kKGRmX3Rhc2sub2RkLCBkZl90YXNrLm9kZF9kcHJpbWUpCmBgYAoKCiMjIFN0YXRzCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHJ1biBtb2RlbHMgaW4gcGFyYWxsZWwKZngucGFyX21vZGVsIDwtIGZ1bmN0aW9uKHNpZ25hbCwgZHYsIGl2LCByZSwgc3ViX2lkLCBmYW0sIGRhdGEpewogICMgUmlnaHQgaGFuZCBmb3JtdWxhOyAjIExlZnQgaGFuZCBmb3JtdWxhCiAgcnNfZm9ybXVsYT1kdjsgCiAgbHNfZm9ybXVsYT0gcGFzdGUoaXYsIHNpZ25hbCwgIHNlcD0iIikKICByZV9mb3JtdWxhPXBhc3RlKCIoIiwgcmUsICJ8Iiwgc3ViX2lkLCIpIiwgc2VwPSIiKQogICMgUHV0IHRvZ2V0aGVyIGFuZHMgcnVuIHRoZSBtb2RlbAogIGZ1bGxfZm9ybT0gcGFzdGUocnNfZm9ybXVsYSwgcGFzdGUobHNfZm9ybXVsYSwgcmVfZm9ybXVsYSwgc2VwPSIrIiksICBzZXA9In4iKQogIGlmIChmYW09PSJsbWVyIil7CiAgICAgIHJ1bl9tb2RlbD1sbWVyKGFzLmZvcm11bGEoZnVsbF9mb3JtKSwKICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3QoU2Vzc2lvbj0iY29udHIudHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9bG1lckNvbnRyb2woY2FsYy5kZXJpdnM9RkFMU0UsIG9wdEN0cmw9bGlzdChtYXhmdW49MTAwMDAwKSwgb3B0aW1pemVyPSJib2J5cWEiKSkKICB9ZWxzZXsKICBydW5fbW9kZWw9Z2xtZXIoYXMuZm9ybXVsYShmdWxsX2Zvcm0pLCAKICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3QoU2Vzc2lvbj0iY29udHIudHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgIGRhdGE9ZGF0YSwKICAgICAgICAgICAgICAgICAgZmFtaWx5PWZhbSwKICAgICAgICAgICAgICAgICAgY29udHJvbD1nbG1lckNvbnRyb2woY2FsYy5kZXJpdnM9RkFMU0UsIG9wdEN0cmw9bGlzdChtYXhmdW49MTAwMDAwKSwgb3B0aW1pemVyPSJib2J5cWEiKSkgfQogIHJldHVybihydW5fbW9kZWwpfQpgYGAKCiMjIyBOYmFjayB7LX0KRm9yIHRoZSBuYmFjaywgd2Ugd2lsbCBsb29rIGF0IHRocmVlIG1lYXN1cmVzOiBUaGUgcmVhY3Rpb24gdGltZSAoUlQpLCB0aGUgbnVtYmVyIG9mIGVycm9ycyAoUEUpLCBhbmQgdGhlIGNvbWJpbmVkIHNjb3JlIHVzaW5nIHRoZSBMSUFTRVMgbWV0aG9kIHRvIGNvbWJpbmUgYWNjdXJhY3kgYW5kIHNwZWVkLiBXZSdsbCBydW4gdGhlIFJUIG1vZGVsIG9uIGluZGl2aWR1YWwgdHJpYWxzIHdoZXJlIHRoZXJlIHdhcyBhIHJlc3BvbnNlIChzbyBvbmx5IHJlc3BvbnNlIHRyaWFscywgd2l0aG91dCBmYWN0b3JpbmcgaW4gZXJyb3JzKS4gV2UgdGhlbiBsb29rIGF0IHRoZSBlcnJvciByYXRlIHVzaW5nIHRoZSBwcm9wb3J0aW9uIG9mIG1pc3NlcyBhbmQgZmFsc2UgYWxhcm1zIGluIHRoZSBvdmVyYWxsIG51bWJlciBvZiB0cmlhbHMsIGFuZCBmaW5hbGx5IHRoZSBMSUFTRVMgdGhhdCBjb21iaW5lcyB0aGVzZSBlZmZlY3RzLCB3aGlsZSBhbHNvIGFjY291bnQgZm9yIHdpdGhpbiBzdWJqZWN0IGRldmlhdGlvbnMuIFRoZXNlIGhhdmUgYWxsIGJlZW4gY2FsY3VsYXRlZCBhYm92ZSwgc28gd2UgY2FuIGp1c3QgYnVpbGQgdGhlIG1vZGVscyBoZXJlLCBhbmQgY2hlY2sgdGhlIHJlc3VsdHMuIAoKPGJyPgo8YnI+CgojIyMjIFJlYWN0aW9uIFRpbWUgey0gLnRhYnNldH0KV2UgZmlyc3QgZmlsdGVyIG91dCB0aGUgbm9uLXJlc3BvbnNlcywgYW5kIHRoZSByZXNwb25zZXMgdGhhdCBhcmUgdG9vIGVhcmx5LkkgYWxzbyB6LXRyYW5zZm9ybSwgYW5kIHJlc2NhbGUgdGhlIHJlc3BvbnNlcyB0byBtYWtlIGl0IGVhc2llciB0byBhcHBseSBkaWZmZXJlbnQgdHlwZXMgb2YgZml0cy4gV2UgdGhlbiBsb29rIGF0IHRoZSBkaXN0cmlidXRpb25zIGFzIHRoYXQgd2lsbCBoZWxwIGZpZ3VyZSBvdXQgdGhlIG9wdGltYWwgbW9kZWxzIHRvIGZpdC4gSXQgYXBwZWFycyB0aGF0IHRoZXJlIGlzIG92ZXJhbGwgbm8gcmVhbCBlZmZlY3Qgb2YgcmVhY3Rpb24gdGltZSwgd2hpY2ggSSBmaW5kIHN0cmFuZ2UgbG9va2luZyBhdCB0aGUgZ3JhcGhzLiBJdHMgT0sgdGhvdWdoIEkgZ3Vlc3MuIFdlIGRvbid0IHJ1biBhbnkgcG9zdC1ob2MgdGVzdHMgZHVlIHRvIG5vIG1haW4gZWZmZWN0cyBpbiBvdXIgbW9kZWwgZWl0aGVyLgoKIyMjIyMgSGlzdC4gey19CmBgYHtyfQojIEZpcnN0IGZpbHRlciBvdXQgdGhlIDAgUlRzCmRmX3Rhc2submJhY2tfcnRzIDwtIHN1YnNldChkZl90YXNrLm5iYWNrLCBydD4yMDApCmRmX3Rhc2submJhY2tfcnRzJHJ0X3ogPC0gc2NhbGUoZGZfdGFzay5uYmFja19ydHMkcnQsIGNlbnRlcj1UUlVFLCBzY2FsZT1UUlVFKQpkZl90YXNrLm5iYWNrX3J0cyRydF9zIDwtIHNjYWxlczo6cmVzY2FsZShkZl90YXNrLm5iYWNrX3J0cyRydF96LCB0bz1jKDAuMDEsNykpCmhpc3QoKGRmX3Rhc2submJhY2tfcnRzJHJ0KSkKCmBgYAoKIyMjIyMgTW9kZWxzIHstIC5hY3RpdmV9CmBgYHtyfQojIENvbnRyYXN0IHRvIGludmVzdGlnYXRlCnNpZ25hbHM9bGlzdCgiIiwgIkVDTiIpCgojIFJ1biBNb2RlbHMgaW4gcGFyYWxsZWwKbW9kZWxzLm5iYWNrX3J0IDwtICBtY21hcHBseShzaWduYWxzLCBGVU49ZnVuY3Rpb24oWCl7ZngucGFyX21vZGVsKHNpZ25hbD1YLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdj0icnRfcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl2PWlmZWxzZShYPT0iIiwgICJTZXNzaW9uKlBoYXNlIiwgIjErU2Vzc2lvbipQaGFzZSoiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmU9aWZlbHNlKFg9PSIiLCAgIjErU2Vzc2lvbipQaGFzZSIsIHBhc3RlKCIxK1Nlc3Npb24qUGhhc2UrIiwgWCwgc2VwPSIiKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9pZD0ic3ViX2lkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtPUdhbW1hKGxpbms9ImludmVyc2UiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl90YXNrLm5iYWNrX3J0cyl9LCBtYy5jb3Jlcz01KQojSFRNTCBPdXRwdXQKdGFiLjJiYWNrX3J0IDwtIHRhYl9tb2RlbChtb2RlbHMubmJhY2tfcnQsIGR2LmxhYmVscz1jKCJTaWduYWwiLCAiU2lnbmFsIH4gRUNOIiksIHNob3cuc3RhdD1ULCBzaG93LnNlPVQpCmtuaXRyOjphc2lzX291dHB1dCh0YWIuMmJhY2tfcnQka25pdHIpCmBgYAo8YnI+Cjxicj4KCgojIyMjIyBQb3N0LUhvYyB7LX0KYGBge3J9Cgpqb2ludF90ZXN0cyhtb2RlbHMubmJhY2tfcnRbWzJdXSwgYnk9YygiU2Vzc2lvbiIsICJQaGFzZSIpKQpgYGAKPGJyPgo8YnI+CgojIyMjIyBQbG90OiBNYWluIHstfQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KZGZfdGFzay5uYmFja19zdW1tIDwtIHN1bW1hcnlTRXdpdGhpbihkYXRhPWRmX3Rhc2submJhY2tfcnRzLCBtZWFzdXJldmFyID0gInJ0IiwgaWR2YXI9InN1Yl9pZCIsIHdpdGhpbnZhcnM9YygiU2Vzc2lvbiIsICJQaGFzZSIpLCBuYS5ybT1GQUxTRSkKZGZfdGFzay5uYmFja19zdW1tJFBoYXNlIDwtIGFzLm51bWVyaWMoZGZfdGFzay5uYmFja19zdW1tJFBoYXNlKQpkZl90YXNrLm5iYWNrX3N1bW0kU2Vzc2lvbiA8LSByZWxldmVsKGRmX3Rhc2submJhY2tfc3VtbSRTZXNzaW9uLCAiU3RyZXNzIikKZ2dwbG90KGRmX3Rhc2submJhY2tfc3VtbSwgYWVzKHg9UGhhc2UsIHk9cnQsIGNvbG9yPVNlc3Npb24sIGZpbGw9U2Vzc2lvbikpICsKICAgIGdlb21fbGluZSgpICsgCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPXJ0LXNlLCB5bWF4PXJ0K3NlLCBjb2xvcj1TZXNzaW9uKSxzaXplPTEsIHdpZHRoPTAuMjAsIG5hLnJtPVQpKyAKICBnZ3RoZW1lMgpgYGAKIDxicj4KPGJyPgoKCgojIyMjIyBQbG90OiBFQ04gUGhhc2Ugey19CmBgYHtyfQpnZ3Bsb3QoZGZfdGFzay5uYmFja19ydHMsIGFlcyh5PXJ0X3MsIHg9RUNOLCBjb2xvdXI9UGhhc2UpKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c3RyZXNzX2NvbG9ycykgKyBnZ3RoZW1lMgpqb2ludF90ZXN0cyhtb2RlbHMubmJhY2tfcnRbWzJdXSwgIGJ5PWMoIlBoYXNlIikpCmVtdHJlbmRzKG1vZGVscy5uYmFja19ydFtbMl1dLCBwYWlyd2lzZSB+IFBoYXNlLCB2YXI9IkVDTiIpCmdncGxvdChkZl90YXNrLm5iYWNrX3J0cywgYWVzKHk9cnRfcywgeD1TTiwgY29sb3VyPVNlc3Npb24pKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c3RyZXNzX2NvbG9ycykgKyBmYWNldF9ncmlkKC5+UGhhc2UpICsgZ2d0aGVtZTIKYGBgCjxicj4KPGJyPgoKCiMjIyMgUHJvcG9ydGlvbiBvZiBFcnJvcnMgey0gLnRhYnNldH0KRm9yIHRoZSBlcnJvciByYXRlcywgd2UgY2FudCByZWFsbHkgdGFrZSB0aGUgdHJpYWwtYnktdHJpYWwgYXBwcm9hY2ggbGlrZSB3ZSBkbyB3aXRoIHRoZSByZWFjdGlvbiB0aW1lcywgc28gaW5zdGVhZCB3ZSB3aWxsIHRha2UgYSBsb29rIGF0IHRoZSBlcnJvciByYXRlcyBwZXIgcnVuL2NvbmRpdGlvbi4gV2UgY2FuIHVzZSB0aGlzIGZpbHRlcmVkIGRhdGEgZnJhbWUgbGF0ZXIgdG9vIGZvciBMSUFTRVMgc2luY2Ugd2UgaGF2ZSBhIHNpbWlsYXIgbWVhc3VyZSBwZXIgc2Vzc2lvbipydW4uIFdlIGZpcnN0IGNhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIGVycm9ycyBpbnN0ZWFkIG9mIHRoZSBwcm9wb3J0aW9uLiBUaGF0cyBtYWlubHkgYmVjYXVzZSB0aGUgcHJvcG9ydGlvbiBkb2Vzbid0IGZpdCB3aWxsIGluIHRoZSBtb2RlbHMsIGFuZCBpc24ndCBhbiBhY2N1cmF0ZSByZXByZXNlbnRhdGlvbiBnaXZlbiB0aGUgemVyby1pbmZsYXRpb24uIFNvIHdlIHVzZSBjb3VudHMgaW5zdGVhZCwgdGhhdCB3YXkgd2UgY2FuIHVzZSBhIFBvaXNzb24gbW9kZWwgd2hpY2ggd291bGQgZml0IHRoZSBkYXRhIG11Y2ggYmV0dGVyLiAKYGBge3J9CiMgU3Vic2V0CmRmX3Rhc2submJhY2tfc3VtIDwtIGRmX3Rhc2submJhY2tfcnRzCmRmX3Rhc2submJhY2tfc3VtIDwtIGRmX3Rhc2submJhY2tfc3VtICU+JSBkcGx5cjo6c2VsZWN0KCJzdWJfaWQiLCAiU2Vzc2lvbiIsICJQaGFzZSIsICJSdW4iLCJydW4iLCAiTElBU0VTIiwicGUiLCAiRkEiLCAiTWlzcyIsICJFQ04iLCAiU04iLCAiU05fRUNOIikgJT4lIGdyb3VwX2J5KHN1Yl9pZCwgU2Vzc2lvbiwgUnVuKSAlPiUgZHBseXI6Om11dGF0ZShGQV9jb3VudD1zdW0oRkEsIG5hLnJtPVRSVUUpLCBNaXNzX2NvdW50PXN1bShNaXNzLCBuYS5ybT1UUlVFKSwgZXJyb3JfY291bnQ9KEZBX2NvdW50K01pc3NfY291bnQpKSAlPiUgdW5ncm91cCgpICU+JSBkcGx5cjo6c2VsZWN0KCJzdWJfaWQiLCAiU2Vzc2lvbiIsICJQaGFzZSIsICJSdW4iLCJydW4iLCAiTElBU0VTIiwicGUiLCAiZXJyb3JfY291bnQiLCAiRUNOIiwgIlNOIiwgIlNOX0VDTiIpICU+JSB1bmlxdWUoKQojIFJlc2NhbGUgdGhlIHZhcmlhYmxlcwpkZl90YXNrLm5iYWNrX3N1bSRMSUFTRVNfeiA8LSBzY2FsZShkZl90YXNrLm5iYWNrX3N1bSRMSUFTRVMsIGNlbnRlcj1UUlVFLCBzY2FsZT1UUlVFKQpkZl90YXNrLm5iYWNrX3N1bSRwZV96IDwtIHNjYWxlKGRmX3Rhc2submJhY2tfc3VtJHBlLCBjZW50ZXI9VFJVRSwgc2NhbGU9VFJVRSkKYGBgCgojIyMjIyBNb2RlbHMgey0gLmFjdGl2ZX0KYGBge3J9CiMgQ29udHJhc3RzIHRvIGludmVzdGlnYXRlCnNpZ25hbHM9bGlzdCgiIiwgIkVDTiIpCiMgUnUgbW9kZGVscyBpbiBwYXJhbGxlbAptb2RlbHMubmJhY2tfcGUgPC0gbWNtYXBwbHkoc2lnbmFscywgRlVOPWZ1bmN0aW9uKFgpe2Z4LnBhcl9tb2RlbChzaWduYWw9WCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHY9ImVycm9yX2NvdW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXY9aWZlbHNlKFg9PSIiLCAgIlNlc3Npb24qUGhhc2UiLCAiMStTZXNzaW9uKlBoYXNlKiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZT1pZmVsc2UoWD09IiIsICAiMStTZXNzaW9uKlBoYXNlIiwgcGFzdGUoIjErU2Vzc2lvbipQaGFzZSsiLCBYLCBzZXA9IiIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViX2lkPSJzdWJfaWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW09cG9pc3NvbigpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX3Rhc2submJhY2tfc3VtKX0sIG1jLmNvcmVzPTUgKQojSFRNTCBPdXRwdXQKdGFiLjJiYWNrX3BlIDwtIHRhYl9tb2RlbChtb2RlbHMubmJhY2tfcGUsIGR2LmxhYmVscz1zaWduYWxzLCBzaG93LnNlPVQsIHNob3cuc3RhdD1UKQphc2lzX291dHB1dCh0YWIuMmJhY2tfcGUka25pdHIpCgpgYGAKPGJyPgo8YnI+CgojIyMjIyBQb3N0LUhvYzogTWFpbiB7LX0KYGBge3J9CmVtbWVhbnMobW9kZWxzLm5iYWNrX3BlW1sxXV0sICBsaXN0KHBhaXJ3aXNlIH5TZXNzaW9uKlBoYXNlKSwgYnk9YygiUGhhc2UiKSwgYWRqdXN0ID0gInR1a2V5IikKYGBgCjxicj4KPGJyPgoKIyMjIyMgUG9zdC1Ib2M6IEJyYWluIHstfQpgYGB7cn0Kam9pbnRfdGVzdHMobW9kZWxzLm5iYWNrX3BlW1syXV0sIGJ5PWMoIlNlc3Npb24iLCAiUGhhc2UiKSkgCmBgYAo8YnI+Cjxicj4KCiMjIyMjIFBsb3Qgey19CmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpkZi5uYmFja19lcnJvcl9zdW0gPC0gc3VtbWFyeVNFd2l0aGluKGRhdGE9ZGZfdGFzay5uYmFja19zdW0sIG1lYXN1cmV2YXI9ImVycm9yX2NvdW50IiwgaWR2YXI9InN1Yl9pZCIsIHdpdGhpbnZhcnM9ICBjKCJQaGFzZSIsICJTZXNzaW9uIiksIG5hLnJtPUZBTFNFKQpkZi5uYmFja19lcnJvcl9zdW0kUGhhc2UgPC0gYXMubnVtZXJpYyhkZi5uYmFja19lcnJvcl9zdW0kUGhhc2UpCmRmLm5iYWNrX2Vycm9yX3N1bSRTZXNzaW9uIDwtIHJlbGV2ZWwoZGYubmJhY2tfZXJyb3Jfc3VtJFNlc3Npb24sICJTdHJlc3MiKQpwbG90Lm5iYWNrX2Vycm9ycyA8LSBnZ3Bsb3QoZGYubmJhY2tfZXJyb3Jfc3VtLCBhZXMoeD1QaGFzZSwgeT1lcnJvcl9jb3VudCwgY29sb3I9U2Vzc2lvbiwgZmlsbD1TZXNzaW9uKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0ic3VtbWFyeSIsIHBvc2l0aW9uPSJkb2RnZTIiLCBhbHBoYT0wLjUpICsgCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWVycm9yX2NvdW50LXNlLCB5bWF4PWVycm9yX2NvdW50K3NlLCBjb2xvcj1TZXNzaW9uKSxzaXplPTEsIHdpZHRoPTAuNDUsIG5hLnJtPVQsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSApICsgZ2d0aGVtZTIKcGxvdC5uYmFja19lcnJvcnMKYGBgCjxicj4KPGJyPgoKIyMjIyBMSUFTRVMgey0gLnRhYnNldH0KVGhlIGZpbmFsIG1lYXN1cmUgd2UgdXNlIHRvIGNhbGN1bGF0ZSB0aGUgbi1iYWNrIHBlcmZvcm1hbmNlIGlzIExJQVNFUywgd2hpY2ggY29tYmluZXMgYWNjdXJhY3kgYW5kIHNwZWVkLiBUaGlzIG1ldGhvZCBpcyBtZW50aW9uZWQgZWFybGllciwgYW5kIGEgZGF0YSBmcmFtZSB3YXMgc3Vic2V0dGVkIGluIHRoZSBjaHVuayBsb29raW5nIGF0IHRoZSBlcnJvciByYXRlcywgc28gd2UganVzdCBuZWVkIHRvIGJ1aWxkIHRoZSBtb2RlbCBhbmQgcnVuIGl0IGhlcmUuIEkgZmlyc3QgdGVzdGVkIGRpZmZlcmVudCBmaXRzLCBhbmQgaXQgYXBwZWFycyB0aGF0IHRoZSBpbnZlcnNlIEdhdXNzaWFuIGlzIHRoZSBiZXN0IHRvIGZpdCB0aGlzIGRhdGEuIAoKCiMjIyMjIEhpc3QuIHstfQpgYGB7cn0KaGlzdCgoZGZfdGFzay5uYmFja19zdW0kTElBU0VTX3opKQpgYGAKPGJyPgo8YnI+CgojIyMjIyBNb2RlbHMgey0gLmFjdGl2ZX0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgUGFyYWxsZWwKc2lnbmFscz1saXN0KCIiLCAgIkVDTiIgKQptb2RlbHMubmJhY2tfbGlhc2VzIDwtIG1jbWFwcGx5KHNpZ25hbHMsIEZVTj1mdW5jdGlvbihYKXtmeC5wYXJfbW9kZWwoc2lnbmFsPVgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR2PSJMSUFTRVNfeiIsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdj1pZmVsc2UoWD09IiIsICAiU2Vzc2lvbipQaGFzZSIsICIxK1Nlc3Npb24qUGhhc2UqIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlPWlmZWxzZShYPT0iIiwgICIxK1Nlc3Npb24qUGhhc2UiLCBwYXN0ZSgiMStTZXNzaW9uKlBoYXNlKyIsIFgsIHNlcD0iIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJfaWQ9InN1Yl9pZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbT1nYXVzc2lhbihsaW5rPSJpbnZlcnNlIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfdGFzay5uYmFja19zdW0pfSwgbWMuY29yZXM9NSkKI0hUTUwgT3V0cHV0CnRhYi4yYmFja19saWFzZXMgPC0gdGFiX21vZGVsKG1vZGVscy5uYmFja19saWFzZXMsIGR2LmxhYmVscz1jKCJTaWduYWwiLCJTaWduYWwgfiBFQ04iICksc2hvdy5zdGF0PVQsIHNob3cuc2U9VCkKYXNpc19vdXRwdXQodGFiLjJiYWNrX2xpYXNlcyRrbml0cikKYGBgCjxicj4KPGJyPgoKIyMjIyMgUG9zdC1Ib2M6IEJlaGF2aW91cmFsIHstfQpgYGB7cn0KZW1tZWFucyhtb2RlbHMubmJhY2tfbGlhc2VzW1sxXV0sIHBhaXJ3aXNlIH4gU2Vzc2lvbiB8IFBoYXNlLCBhZGp1c3Q9Im5vbmUiKQpgYGAKPGJyPgo8YnI+CgojIyMjIyBQbG90OiBCZWhhdmlvcmFsIHstfQpgYGB7cn0KZGZfdGFzay5uYmFja19zdW1tIDwtIHN1bW1hcnlTRXdpdGhpbihkZl90YXNrLm5iYWNrLCBtZWFzdXJldmFyPSJMSUFTRVMiLCBpZHZhcj0ic3ViX2lkIiwgd2l0aGludmFyPWMoIlNlc3Npb24iLCAiUGhhc2UiKSwgbmEucm09VCkKZGZfdGFzay5uYmFja19zdW1tJHJ1biA8LSBhcy5udW1lcmljKGRmX3Rhc2submJhY2tfc3VtbSRQaGFzZSkKZGZfdGFzay5uYmFja19zdW1tJFNlc3Npb24gPC0gcmVsZXZlbChkZl90YXNrLm5iYWNrX3N1bW0kU2Vzc2lvbiwgIlN0cmVzcyIpCmdncGxvdChkZl90YXNrLm5iYWNrX3N1bW0sIGFlcyh4PXJ1biwgeT1MSUFTRVMsIGNvbG9yPVNlc3Npb24sIGZpbGw9U2Vzc2lvbikpICsKICAgIGdlb21fbGluZSgpICsgCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPUxJQVNFUy1zZSwgeW1heD1MSUFTRVMrc2UsIGNvbG9yPVNlc3Npb24pLHNpemU9MC41LCB3aWR0aD0wLjE1LCBuYS5ybT1UKSArIAogIGdndGhlbWUyIApgYGAKPGJyPgo8YnI+CgojIyMjIyBQb3N0LUhvYzogRUNOIGJ5IFNlc3Npb24gey19CmBgYHtyfQplbXRyZW5kcyhtb2RlbHMubmJhY2tfbGlhc2VzW1syXV0sIGlkZW50aXR5IH4gU2Vzc2lvbiwgdmFyPSJFQ04iKQojZW10cmVuZHMobW9kZWxzLm5iYWNrX2xpYXNlc1tbM11dLCBwYWlyd2lzZSB+IFNlc3Npb24gfCBQaGFzZSwgdmFyPSJFQ04iKQpgYGAKCgpgYGB7cn0KZ2dwbG90KGRmX3Rhc2submJhY2tfc3VtLCBhZXMoeD1FQ04sIHk9TElBU0VTX3osIGNvbG91cj1TZXNzaW9uKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBzZT1UKSArIAogIHhsYWIoIkVDTiBBY3Rpdml0eSIpICsgeWxhYigiTElBU0VTIEFjY3VyYWN5IFNjb3JlIikgKwogIGdndGhlbWUyICArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c3RyZXNzX2NvbG9ycykKYGBgCjxicj4KCgoKIyMjIE1lbW9yeSB7LX0KRm9yIHRoZSBtZW1vcnkgdGFzaywgd2UgbG9vayBhdCB0aGUgcmVhY3Rpb24gdGltZSB0byB0aGUgc3RpbXVsaSwgc3BsaXQgYnkgdmFsZW5jZSwgYW5kIHRoZSByZWNvZ25pdGlvbiBvZiB0aGUgaW1hZ2VzIHdlIHByZXNlbnRlZCB0aGVtIHdpdGggb3V0c2lkZSB0aGUgc2Nhbm5lci4gRm9yIHRoZSBSVCBkYXRhLCB3ZSB3aWxsIHRha2UgYSBsb29rIGF0IGluZGl2aWR1YWwgdHJpYWxzLCBhbmQgdGhlbiBmb3IgdGhlIHJlY29nbml0aW9uIG9mIHRoZSBpbWFnZXMgd2UgdGFrZSBhIGxvb2sgYXQgdGhlIGF2ZXJhZ2UgcmVwb3NlcyBwZXIgcnVuIG9yIHBoYXNlLCBkZXBlbmRpbmcgb24gdGhlIG1vZGVsIGZpdHMgYmVzdC4gV2UgZmlyc3QgYWxzbyByZW1vdmUgYW55IHJ0cyB0aGF0IGFyZSBsZXNzIHRoYW4gMjAwbXMgYXMgdGhvc2UgYXJlIGp1c3QgdG9vIHF1aWNrLCBhbmQgd2UgYWxzbyByZXNjYWxlIHRoZSBSVCB2YXJpYWJsZXMuIApgYGB7cn0KZGZfdGFzay5tZW0gPC0gZGZfdGFzay5tZW0gJT4lIHN1YnNldChydD49MjAwKQpkZl90YXNrLm1lbSRydF96IDwtIHNjYWxlKGRmX3Rhc2subWVtJHJ0KQpkZl90YXNrLm1lbSRydF9zIDwtIHNjYWxlczo6cmVzY2FsZShkZl90YXNrLm1lbSRydF96LCB0bz1jKDEsNikpCmBgYAoKCiMjIyMgUmVjb2duaXRpb24gey0gLnRhYnNldH0KV2UgbmV4dCBsb29rIGF0IHRoZSBhYmlsaXR5IHRvIHJlY2FsbCB0aGUgb2JqZWN0LWxvY2F0aW9uIGFzc29jaWF0aW9ucy4gV2UgZmlyc3Qgd2lsbCBsb29rIGF0IG92ZXJhbGwgcmVjYWxsLCB0aGVuIHRha2UgYSBsb29rIGF0IHRoZSByZWNhbGwgYnkgdmFsZW5jZSBhc3NvY2lhdGlvbnMgdG8gc2VlIGlmIHRoZSBuZWdhdGl2ZSBvciBwb3NpdGl2ZWx5IHZhbGVudCBpbWFnZXMgYXJlIHJlbWVtYmVyZWQgYmV0dGVyLiBGaXJzdCBJIHN1YnNldCB0aGUgZGF0YSwgYW5kIG1ha2UgdGhlIGRhdGEgZnJhbWUgYSBiaXQgbG9uZ2VyIHNvIHRoYXQgd2UgaGF2ZSBwZXJjZW50IGNvcnJlY3QgZm9yIGVhY2ggb2YgdGhlIG5ldXRyYWwgYW5kIHRoZSBuZWdhdGl2ZSBpdGVtcyBpbiBvbmUgY29sdW1uLiAKYGBge3J9CiMgU3Vic2V0IHRoZSBuZXV0cmFsIGl0ZW0gY29ycmVjdCByZXNwb25zZSByYXRlcwpkZl90YXNrLm1lbV9uZXUgPC0gZGZfdGFzay5tZW0gJT4lIGRwbHlyOjpzZWxlY3QoInN1Yl9pZCIsICJTZXNzaW9uIiwgIlBoYXNlIiwgIlJ1biIsInJ1biIsICJtZW1fbmV1X3BlciIsICJETU4iKSAlPiUgdW5pcXVlKCkgJT4lIGRwbHlyOjpyZW5hbWUocGVyX2Nvcj1tZW1fbmV1X3BlcikgJT4lIG11dGF0ZSh2YWxlbmNlPSJuZXUiKQojIERvIHRoZSBzYW1lIGZvciB0aGUgbmVnYXRpdmUgaXRlbXMKZGZfdGFzay5tZW1fbmVnIDwtIGRmX3Rhc2subWVtICU+JSBkcGx5cjo6c2VsZWN0KCJzdWJfaWQiLCAiU2Vzc2lvbiIsICJQaGFzZSIsICJSdW4iLCJydW4iLCAibWVtX25lZ19wZXIiLCAiRE1OIikgJT4lIHVuaXF1ZSgpICU+JSBkcGx5cjo6cmVuYW1lKHBlcl9jb3I9bWVtX25lZ19wZXIpICAlPiUgbXV0YXRlKHZhbGVuY2U9Im5lZyIpCiMgQmluZCB0aGVtIGludG8gb25lIGRhdGFmcmFtZQpkZl90YXNrLm1lbV9jb3IgPC0gcmJpbmQuZGF0YS5mcmFtZShkZl90YXNrLm1lbV9uZWcsIGRmX3Rhc2subWVtX25ldSkKYGBgCgpOb3cgd2UgY2FuIGFsc28gY2hlY2sgb3V0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGNvcnJlY3QgcmVzcG9uc2UgcmF0ZXMgZm9yIGVhY2ggb2YgdGhlIHZhbGVuY2VzIHRvIGhlbHAgcGljayB0aGUgbW9zdCBzdWl0YWJsZSBtb2RlbCBmYW1pbHkuIFdlIHNlZSB0aGF0IGJvdGggdmFsZW5jZXMgbG9vayBzaW1pbGFyLCBidXQgc2tld2VkIGxlZnQuIAoKIyMjIyMgSGlzdC4gey19CmBgYHtyfQpoaXN0KGRmX3Rhc2subWVtX25ldSRwZXJfY29yKQpoaXN0KGRmX3Rhc2subWVtX25lZyRwZXJfY29yKQpgYGAKPGJyPgo8YnI+CiAKIyMjIyMgQ2hhbmNlIExldmVsIHstfQpgYGB7cn0KbW9kZWwubWVtb3J5X2NoYW5jZSA8LSB0LnRlc3QoZGZfdGFzay5tZW0kbWVtX3RvdF9wZXIsIG11PTAuMjUpCnRpZHkobW9kZWwubWVtb3J5X2NoYW5jZSkKYGBgCjxicj4KPGJyPgogCgojIyMjIyBNb2RlbHMgey0gLmFjdGl2ZX0KYGBge3J9CiMgTWFpbgptb2RlbC5tZW1fY29ycmVjdCA8LSBsbWVyKHBlcl9jb3IgfiBTZXNzaW9uKlBoYXNlKnZhbGVuY2UgKyAoMStTZXNzaW9uKlBoYXNlfHN1Yl9pZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3QoU2Vzc2lvbj0iY29udHIudHJlYXRtZW50IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfdGFzay5tZW1fY29yLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sPWxtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRkFMU0UsIG9wdEN0cmw9bGlzdChtYXhmdW49MTAwMDAwKSkgKQojY2hlY2tfbW9kZWwobW9kZWwubWVtX2NvcnJlY3QpCiMgQnJhaW4KbW9kZWwubWVtX2NvcnJlY3RfYnJhaW4gPC0gbG1lcihwZXJfY29yIH4gU2Vzc2lvbipQaGFzZSpETU4gKyB2YWxlbmNlICsgKDErU2Vzc2lvbipQaGFzZSpETU58c3ViX2lkKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChTZXNzaW9uPSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl90YXNrLm1lbV9jb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9bG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGQUxTRSwgb3B0aW1pemVyPSJib2J5cWEiLCBvcHRDdHJsPWxpc3QobWF4ZnVuPTEwMDAwMCkpICkKIyBIVE0gVGFibGUKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVsLm1lbV9jb3JyZWN0LCBtb2RlbC5tZW1fY29ycmVjdF9icmFpbikka25pdHIpCmBgYAo8YnI+Cjxicj4KIAojIyMjIyBQb3N0LUhvYzogTWFpbiB7LX0KT25seSB0aGUgdmFsZW5jZSBlZmZlY3Qgc3RpY2tzIG91dCwgc28gd2UgcnVuIGEgc3BlY2lmaWMgcG9zdC1ob2MgdGVzdCB0byBpbnZlc3RpZ2F0ZSBpdCBmdXJ0aGVyLgpgYGB7cn0KZW1tZWFucyhtb2RlbC5tZW1fY29ycmVjdCwgIGxpc3QocGFpcndpc2UgflNlc3Npb24qdmFsZW5jZSksIGJ5PWMoIlBoYXNlIiksIGFkanVzdCA9ICJ0dWtleSIpCmBgYAo8YnI+Cjxicj4KIAojIyMjIyBQbG90OiBNYWluIHstfQpgYGB7cn0KZGZfdGFzay5tZW1fY29yX3N1bSA8LSBzdW1tYXJ5U0V3aXRoaW4oZGF0YT1kZl90YXNrLm1lbV9jb3IsIGlkdmFyPSJzdWJfaWQiLCBtZWFzdXJldmFyPSJwZXJfY29yIiwgd2l0aGludmFycz1jKCJTZXNzaW9uIiwiUGhhc2UiLCJ2YWxlbmNlIikpCnBsb3QubWVtX2NvcnIgPC0gZ2dwbG90KGRmX3Rhc2subWVtX2Nvcl9zdW0sIGFlcyh5PXBlcl9jb3IsIHg9UGhhc2UsIGNvbG91cj12YWxlbmNlLCBmaWxsPXZhbGVuY2UsIG5hLnJtID0gVFJVRSkpICsKICBnZW9tX2JhcihzdGF0PSJzdW1tYXJ5IiwgYWxwaGE9LjUsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlMigpKSsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPXBlcl9jb3Itc2UsIHltYXg9cGVyX2NvcitzZSksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSxzaXplPTEsIHdpZHRoPTAuNDUsIG5hLnJtPVQpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoKSsgc2NhbGVfeF9kaXNjcmV0ZSgpKwogIGdndGl0bGUoIlBpY3R1cmUtTG9jYXRpb24gUmVjYWxsIikrCiAgeWxhYigiUGVyY2VudCBSZW1lbWJlcmVkXG4iKSArIAogIGdndGhlbWUyIApwbG90Lm1lbV9jb3JyICsgZmFjZXRfZ3JpZCguflNlc3Npb24pCmBgYAo8YnI+Cjxicj4KIAojIyMjIyBQb3N0LUhvYzogRE1OIGJ5IFBoYXNlIHstfQpgYGB7cn0KZW10cmVuZHMobW9kZWwubWVtX2NvcnJlY3RfYnJhaW4sIHBhaXJ3aXNlIH4gUGhhc2UsIHZhcj0iRE1OIikgCmBgYAoKYGBge3J9CmVtbWlwKG1vZGVsLm1lbV9jb3JyZWN0X2JyYWluLCBQaGFzZSB+IERNTiwgY292LnJlZHVjZSA9IHJhbmdlKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c3RyZXNzX2NvbG9ycykgKyBnZ3RoZW1lMgpgYGAKCjxicj4KPGJyPgogCgojIyMjIFJlYWN0aW9uIFRpbWUgey0gLnRhYnNldH0KV2UgZmlyc3QgdGFrZSBhIGxvb2sgYXQgdGhlIHJlYWN0aW9uIHRpbWUuIFRoaXMgYW5hbHlzaXMgaXMgZG9uZSBvbiBhIHRyaWFsIGJ5IHRyaWFsIGJhc2lzLiBXZSB3aWxsIGxvb2sgYXQgdGhlIFJUIGJldHdlZW4gdGhlIHN0cmVzcyBhbmQgY29udHJvbCBzZXNzaW9ucywgYW5kIGFsc28gbG9vayBhdCB0aGUgZWZmZWN0cyBvZiB0aGUgdmFsZW5jZSBvZiB0aGUgaW1hZ2VzIG9uIHRoZSByZWFjdGlvbiB0aW1lLiBGaXJzdCB3ZSB0YWtlIGEgbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBSVCdzIHRvIGJldHRlciBpbmZvcm0gdXMgb2Ygd2hpY2ggbW9kZWwgZmFtaWx5IHdvdWxkIGZpdCBiZXN0LiBJdCBhcHBlYXJzIGhlcmUgdGhhdCB3ZSBoYXZlIGEgc2lnbmlmaWNhbnQgZWZmZWN0IG9mIHZhbGVuY2Ugb24gcmVhY3Rpb24gdGltZXMuIFNvIHBhcnRpY2lwYW50cyBhcmUgZmFzdGVyIGluIHJlc3BvbmRpbmcuCgojIyMjIyBIaXN0LiB7LX0KYGBge3J9Cmhpc3QoZGZfdGFzay5tZW0kcnQpCmBgYAo8YnI+Cjxicj4KIAojIyMjIyBNb2RlbHMgey0gLmFjdGl2ZX0KYGBge3J9CiMgTWFpbgptb2RlbC5tZW1vcnlfcnQgPC0gZ2xtZXIocnRfcyB+IFNlc3Npb24qUGhhc2UgKyBTZXNzaW9uKnZhbGVuY2UgK1Nlc3Npb24qUGhhc2UqdmFsZW5jZSArICgxK1Nlc3Npb24qUGhhc2V8c3ViX2lkKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KFNlc3Npb249ImNvbnRyLnRyZWF0bWVudCIpLAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX3Rhc2subWVtLAogICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHk9R2FtbWEoImludmVyc2UiKSwKICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sPWdsbWVyQ29udHJvbChjYWxjLmRlcml2cz1GQUxTRSkpCiMgQnJhaW4KbW9kZWwubWVtb3J5X3J0X2JyYWluIDwtIGdsbWVyKHJ0X3MgfiBTZXNzaW9uKlBoYXNlKkRNTiArICgxK1Nlc3Npb24qUGhhc2UqRE1OfHN1Yl9pZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChTZXNzaW9uPSJjb250ci50cmVhdG1lbnQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl90YXNrLm1lbSwKICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHk9R2FtbWEoImlkZW50aXR5IiksCiAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbD1nbG1lckNvbnRyb2woY2FsYy5kZXJpdnM9RkFMU0UsIG9wdGltaXplcj0iYm9ieXFhIiwgb3B0Q3RybD1saXN0KG1heGZ1bj0xMDAwMDApKSkKIyBIVE1MIE91dHB1dAphc2lzX291dHB1dCh0YWJfbW9kZWwobW9kZWwubWVtb3J5X3J0LCBtb2RlbC5tZW1vcnlfcnRfYnJhaW4pJGtuaXRyKQpgYGAKPGJyPgo8YnI+CiAKIyMjIyMgUG9zdC1Ib2M6IE1haW4gey19CmBgYHtyfQplbW1lYW5zKG1vZGVsLm1lbW9yeV9ydCwgIGxpc3QocGFpcndpc2UgfiBTZXNzaW9uKlBoYXNlKSwgYnk9YygiUGhhc2UiKSwgYWRqdXN0ID0gInR1a2V5IikKYGBgCjxicj4KPGJyPgogCgojIyMjIyBQbG90OiBNYWluIHstfQpgYGB7cn0KZGZfdGFzay5tZW1fc3VtIDwtIHN1bW1hcnlTRXdpdGhpbihkZl90YXNrLm1lbSwgbWVhc3VyZXZhcj0icnQiLGlkdmFyPSJzdWJfaWQiLCB3aXRoaW52YXJzPSBjKCJTZXNzaW9uIiwiUGhhc2UiLCJ2YWxlbmNlIikpCmRmX3Rhc2subWVtX3N1bSRydW4gPSBhcy5udW1lcmljKChkZl90YXNrLm1lbV9zdW0kUGhhc2UpKQpkZl90YXNrLm1lbV9zdW0kdmFsZW5jZSA8LSByZWxldmVsKGRmX3Rhc2subWVtX3N1bSR2YWxlbmNlLCAibmVnYXRpdmUiKQpwbG90Lm1lbV9ydCA8LSBnZ3Bsb3QoZGZfdGFzay5tZW1fc3VtLCBhZXMoeD1ydW4sIHk9cnQsIGNvbG91cj12YWxlbmNlKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1ydCtzZSwgeW1heD1ydC1zZSksd2lkdGg9MC4yLCBuYS5ybT1UUlVFKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxLDIpLCBsYWJlbHMgPSBjKCJFYXJseSIsICJMYXRlIikpICsgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2d0aGVtZTIgIApwbG90Lm1lbV9ydCArIGZhY2V0X2dyaWQoLn5TZXNzaW9uKQpgYGAKPGJyPgo8YnI+CiAKIyMjIyMgUG9zdC1Ib2M6IEJyYWluIHstfQpgYGB7cn0Kam9pbnRfdGVzdHMobW9kZWwubWVtb3J5X3J0X2JyYWluLCBieT1jKCJTZXNzaW9uIiwiUGhhc2UiKSkKZ2dwbG90KGRmX3Rhc2subWVtLCBhZXMoeD1ETU4sIHk9cnRfcywgY29sb3VyPVNlc3Npb24pKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIGdndGhlbWUyICsgIGZhY2V0X2dyaWQoLn5QaGFzZSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXN0cmVzc19jb2xvcnMpCmBgYAo8YnI+Cjxicj4KIAoKIyMjIE9kZGJhbGwgey19ClRoZSBvZGRiYWxsIGRhdGEgaGFzIGFscmVhZHkgYmVlbiBwcm9jZXNzZWQsIHRoZXJlcyBub3QgbXVjaCBtb3JlIHdlIG5lZWQgdG8gZG8gdGhlcmUuIFRoZXJlZm9yZSwgd2UgY2FuIGJlZ2luIHdpdGggdGhlIHN0YXRzLiAKCgojIyMjIGQtUHJpbWUgey0gLnRhYnNldH0KCiMjIyMjIEhpc3QuIHstfQpgYGB7cn0KaGlzdChkZl90YXNrLm9kZCRkcHJpbWUpCmBgYAo8YnI+Cjxicj4KIAojIyMjIyBNb2RlbHMgey0gLmFjdGl2ZX0KYGBge3J9CiMgU2lnbmFscwpzaWduYWxzPWMoIiIsICJTTiIgKQojIFJ1biBpbiBwYXJhbGxlbCBmdW5jdGlvbgptb2RlbHMub2RkX2RwcmltZSA8LSBtY21hcHBseShzaWduYWxzLCBGVU49ZnVuY3Rpb24oWCl7ZngucGFyX21vZGVsKHNpZ25hbD1YLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdj0iZHByaW1lIiwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl2PWlmZWxzZShYPT0iIiwgICJTZXNzaW9uKlJ1biIsICIxK1Nlc3Npb24qUnVuKiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZT1pZmVsc2UoWD09IiIsICAiMStTZXNzaW9uK1J1biIsIHBhc3RlKCIxK1Nlc3Npb24rUnVuIikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJfaWQ9InN1Yl9uciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbT0ibG1lciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfdGFzay5vZGQpfSwgbWMuY29yZXM9NSkKIyBQcmludCBIVE1MIE91dHB1dAphc2lzX291dHB1dCh0YWJfbW9kZWwobW9kZWxzLm9kZF9kcHJpbWUsIGR2LmxhYmVscyA9IGMoIlNpZ25hbCIsICJTaWduYWwgfiBTTiIpLCBzaG93LnN0YXQgPVQsIHNob3cuc2U9VCkka25pdHIpCmBgYAo8YnI+Cjxicj4KIAojIyMjIyBQbG90OiBNYWluIHstfQpgYGB7cn0KcGxvdC5vZGRfc2VzcyA8LSBnZ3Bsb3QoZGZfdGFzay5vZGQsIGFlcyh4PVNjYW4sIHk9ZHByaW1lLCBjb2xvdXI9U2NhbiwgZmlsbD1TY2FuKSkgKyAKICAgIGdlb21fdmlvbGluKGFscGhhPTAuNSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aD0wLjEsIGFscGhhPTAuMikgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGNvbG91cj0iZ3JleSIpICsKICAgIGdndGhlbWUyCnBsb3Qub2RkX3Nlc3MKYGBgCjxicj4KPGJyPgogCiMjIyMjIFBvc3QtSG9jOiBCcmFpbiB7LX0KYGBge3J9CmpvaW50X3Rlc3RzKG1vZGVscy5vZGRfZHByaW1lW1syXV0sIGJ5PWMoIlNlc3Npb24iLCAiUnVuIikpCmBgYAo8YnI+Cjxicj4KIAoKIyMjIyBIaXRzIHstIC50YWJzZXR9CgojIyMjIyBIaXN0LiB7LX0KV2UgZmlyc3QgY2hlY2sgdGhlIGhpdHMuIEl0IGFwcGVhcnMgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIGhpdC1yYXRlIGJldHdlZW4gdGhlIHR3byBzZXNzaW9ucywgYW5kIGJldHdlZW4gdGhlIHJ1bnMuCmBgYHtyfQpoaXN0KGRmX3Rhc2sub2RkJG9kZF9oaXRzKQpgYGAKPGJyPgo8YnI+CiAKIyMjIyMgTW9kZWxzIHstIC5hY3RpdmV9CmBgYHtyfQojIENvbnRyYXN0cyB0byBpbnZlc3RpZ2F0ZQpzaWduYWxzPWMoIiIsICJTTiIpCiMgUnVuIGluIHBhcmFsbGVsIGZ1bmN0aW9uCm1vZGVscy5vZGRfaGl0cyA8LSBtY21hcHBseShzaWduYWxzLCBGVU49ZnVuY3Rpb24oWCl7ZngucGFyX21vZGVsKHNpZ25hbD1YLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdj0ib2RkX2hpdHMiLCAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXY9aWZlbHNlKFg9PSIiLCAgIlNlc3Npb24qUnVuIiwgIjErU2Vzc2lvbipSdW4qIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlPWlmZWxzZShYPT0iIiwgICIxK1Nlc3Npb24rUnVuIiwgcGFzdGUoIjErU2Vzc2lvbitSdW4iKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9pZD0ic3ViX25yIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtPSJsbWVyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl90YXNrLm9kZCl9LCBtYy5jb3Jlcz01KQoKIyBQcmludCBIVE1MIE91dHB1dAphc2lzX291dHB1dCh0YWJfbW9kZWwobW9kZWxzLm9kZF9oaXRzLCBkdi5sYWJlbHMgPSBjKCJTaWduYWwiLCAiU2lnbmFsIH4gU04iKSwgc2hvdy5zdGF0ID1ULCBzaG93LnNlPVQpJGtuaXRyKQpgYGAKPGJyPgo8YnI+CiAKIyMjIyMgUGxvdDogTWFpbiB7LX0KYGBge3J9CnBsb3Qub2RkX2hpdHMgPC0gZ2dwbG90KGRmX3Rhc2sub2RkLCBhZXMoeD1TY2FuLCB5PW9kZF9oaXRzLCBjb2xvdXI9U2NhbiwgZmlsbD1TY2FuKSkgKyAKICAgIGdlb21fdmlvbGluKGFscGhhPTAuNSkgKyAKICAgIGdlb21fYm94cGxvdCh3aWR0aD0wLjEsIGFscGhhPTAuMikgKwogICAgZ2d0aGVtZTIKcGxvdC5vZGRfaGl0cyAKYGBgCjxicj4KPGJyPgogCiMjIyMjIFBvc3QtSG9jOiBCcmFpbiB7LX0KYGBge3J9CmpvaW50X3Rlc3RzKG1vZGVscy5vZGRfaGl0c1tbMl1dLCBieT1jKCJTZXNzaW9uIiwgIlJ1biIpKSAKYGBgCjxicj4KPGJyPgogCiMjIyMgRmFsc2UgQWxhcm1zIHstIC50YWJzZXR9CldlIGFsc28gc2VlIHRoYXQgdGhleSBwZXJmb3JtIG1vcmUgZXJyb3JzLiBTbyB3ZSBoYXZlIGRlY3JlYXNlZCBoaXRzLCBhbmQgbW9yZSBlcnJvcnMgaW4gdGhlIHN0cmVzcyBzZXNzaW9uIAoKCiMjIyMjIE1vZGVscyB7LSAuYWN0aXZlfQpgYGB7cn0KIyBNTG9vcCBvdmVyCnNpZ25hbHM9YygiIiwgIlNOIikKIyBSdW4gaW4gcGFyYWxsZWwgZnVuY3Rpb24KbW9kZWxzLm9kZF9mYXMgPC0gbWNtYXBwbHkoc2lnbmFscywgRlVOPWZ1bmN0aW9uKFgpe2Z4LnBhcl9tb2RlbChzaWduYWw9WCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHY9Im9kZF9GQSIsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdj1pZmVsc2UoWD09IiIsICAiU2Vzc2lvbipSdW4iLCAiMStTZXNzaW9uKlJ1bioiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmU9aWZlbHNlKFg9PSIiLCAgIjErU2Vzc2lvbitSdW4iLCBwYXN0ZSgiMStTZXNzaW9uK1J1biIpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViX2lkPSJzdWJfbnIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW09ImxtZXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX3Rhc2sub2RkKX0sIG1jLmNvcmVzPTUpCiMgSFRNTCBPdXRwdXQKdGFiLm9kZF9mYXMgPC0gdGFiX21vZGVsKG1vZGVscy5vZGRfZmFzLCBzaG93LnNlPVQsIHNob3cuc3RhdD1ULCBkdi5sYWJlbHM9YygiU2lnbmFsIiwgIlNpZ25hbCB+IFNOIikpCmFzaXNfb3V0cHV0KHRhYi5vZGRfZmFzJGtuaXRyKQpgYGAKPGJyPgo8YnI+CiAKCiMjIyMjIFBsb3Q6IE1haW4gey19CmBgYHtyfQpwbG90Lm9kZF9mYXMgPC0gZ2dwbG90KGRmX3Rhc2sub2RkLCBhZXMoeD1TY2FuLCB5PW9kZF9GQSwgY29sb3VyPVNjYW4sIGZpbGw9U2NhbikpICsgCiAgICBnZW9tX3Zpb2xpbihhbHBoYT0wLjUpICsgCiAgICBnZW9tX2JveHBsb3Qod2lkdGg9MC4xLCBhbHBoYT0wLjIpICsKICAgIGdndGhlbWUyCnBsb3Qub2RkX2ZhcwpgYGAKPGJyPgo8YnI+CiAKCiMjIyMjIFBvc3QtSG9jOiBTTiBieSBTZXNzaW9uIHstfQpgYGB7cn0KZW10cmVuZHMobW9kZWxzLm9kZF9mYXNbWzJdXSwgcGFpcndpc2UgfiBTZXNzaW9uLCB2YXI9IlNOIikKam9pbnRfdGVzdHMobW9kZWxzLm9kZF9mYXNbWzJdXSwgYnk9YygiU2Vzc2lvbiIpKQpgYGAKYGBge3J9CnBsb3Quc25fZmFzIDwtIGdncGxvdChkZl90YXNrLm9kZCwgYWVzKHg9U04sIHk9b2RkX0ZBLCBjb2xvdXI9U2Vzc2lvbiwgZmlsbD1TZXNzaW9uKSkgKyAKICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgZm9ybXVsYT0ieX54IiwgYWxwaGE9MC4xNSkgKyAKICAjZ2VvbV9wb2ludChhbHBoYT0wLjUpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9c3RyZXNzX2NvbG9ycykgKyAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXN0cmVzc19jb2xvcnMpICsgCiAgeWxhYigiRmFsc2UgQWxhcm1zIikgKwogIGdndGhlbWUyCnBsb3Quc25fZmFzICsgZmFjZXRfZ3JpZCh+UnVuKQpgYGAKCgo8YnI+Cjxicj4KIAoKIyMjIyBkUHJpbWUgYnkgVmFsZW5jZSB7LSAudGFic2V0fQpOb3cgd2UgdGFrZSBhIGxvb2sgYXQgdGhlIGVmZmVjdHMgb2Ygc3RyZXNzIGFuZCB2YWxlbmNlIG9uIHJlY2FsbC4gU28gd2UgZG8gc29tZXRoaW5nIHNpbWlsYXIgaGVyZSB0byB3aGF0IHdlIGRpZCBiZWZvcmUsIHdoZXJlIHdlIHNwbGl0IHRoZSBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgdmFsdWVzLCBhbmQgdGhlbiBtZXJnZSB0aGVtIGludG8gYSBsb25nIGRhdGEgZnJhbWUoc2FtZSBhcyB3ZSBkaWQgZm9yIHRoZSBtZW1vcnkgdGFzayByZWNvZ25pdGlvbiB0cmlhbHMpLgpgYGB7cn0KIyBTdWJzZXQgdGhlIG5ldXRyYWwgaXRlbSBjb3JyZWN0IHJlc3BvbnNlIHJhdGVzCmRmX3Rhc2sub2RkX3BvcyA8LSBkZl90YXNrLm9kZCAlPiUgZHBseXI6OnNlbGVjdCgic3ViX25yIiwgIlNlc3Npb24iLCAiUnVuIiwgIlNjYW4iLCJkcHJpbWVfcG9zIiwgIlNOIiwgIkVDTiIsICJTTl9FQ04iKSAlPiUgdW5pcXVlKCkgJT4lIGRwbHlyOjpyZW5hbWUoZHByaW1lPWRwcmltZV9wb3MpICU+JSBtdXRhdGUoVmFsZW5jZT0iUG9zaXRpdmUiKQojIERvIHRoZSBzYW1lIGZvciB0aGUgbmVnYXRpdmUgaXRlbXMKZGZfdGFzay5vZGRfbmVnIDwtIGRmX3Rhc2sub2RkICU+JSBkcGx5cjo6c2VsZWN0KCJzdWJfbnIiLCAiU2Vzc2lvbiIsICJSdW4iLCAiU2NhbiIsImRwcmltZV9uZWciLCAiU04iLCAiRUNOIiwgIlNOX0VDTiIpICU+JSB1bmlxdWUoKSAlPiUgZHBseXI6OnJlbmFtZShkcHJpbWU9ZHByaW1lX25lZykgJT4lIG11dGF0ZShWYWxlbmNlPSJOZWdhdGl2ZSIpCiMgQmluZCB0aGVtIGludG8gb25lIGRhdGFmcmFtZQpkZl90YXNrLm9kZF92YWwgPC0gcmJpbmQuZGF0YS5mcmFtZShkZl90YXNrLm9kZF9wb3MsIGRmX3Rhc2sub2RkX25lZykKYGBgCgojIyMjIyBNb2RlbHMgey0gLmFjdGl2ZX0KYGBge3J9CiMgTG9vcCBvdmVyIHRoZXNlCnNpZ25hbHM9YygiIiwgIlNOIikKIyBSdW4gaW4gcGFyYWxsZWwgZnVuY3Rpb24KbW9kZWxzLm9kZF92YWwgPC0gbWNtYXBwbHkoc2lnbmFscywgRlVOPWZ1bmN0aW9uKFgpe2Z4LnBhcl9tb2RlbChzaWduYWw9WCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHY9ImRwcmltZSIsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdj1pZmVsc2UoWD09IiIsICAiU2Vzc2lvbipSdW4qVmFsZW5jZSIsICIxK1Nlc3Npb24qUnVuKlZhbGVuY2UqIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlPWlmZWxzZShYPT0iIiwgICIxK1Nlc3Npb24rUnVuIiwgcGFzdGUoIjErU2Vzc2lvbitSdW4iKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9pZD0ic3ViX25yIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtPSJsbWVyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl90YXNrLm9kZF92YWwpfSwgbWMuY29yZXM9NSkKCiMgUHJpbnQgSFRNTCBPdXRwdXQKYXNpc19vdXRwdXQodGFiX21vZGVsKG1vZGVscy5vZGRfdmFsLCAKICAgICAgICAgICAgICAgICAgICAgIGR2LmxhYmVscyA9IGMoIlNpZ25hbCIsICJTaWduYWwgfiBTTiIpLAogICAgICAgICAgICAgICAgICAgICAgc2hvdy5zdGF0ID1ULCBzaG93LnNlPVQpJGtuaXRyKQpgYGAKPGJyPgo8YnI+CiAKIyMjIyMgUGxvdDogTWFpbiB7LX0KYGBge3J9CnBsb3Qub2RkX3ZhbGVuY2UgPC0gZ2dwbG90KGRmX3Rhc2sub2RkX3ZhbCwgYWVzKHg9U2NhbiwgeT1kcHJpbWUsIGNvbG91cj1TY2FuLCBmaWxsPVNjYW4pKSArIAogICAgZ2VvbV92aW9saW4oYWxwaGE9MC41KSArIAogICAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMSwgYWxwaGE9MC4yKSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgY29sb3VyPSJncmV5IikgKwogICAgZ2d0aGVtZTIKcGxvdC5vZGRfdmFsZW5jZSArIGZhY2V0X2dyaWQoLiB+IFZhbGVuY2UpCmBgYAo8YnI+Cjxicj4KIAojIyMjIyBQb3N0LUhvYzogQnJhaW4gey19CmBgYHtyfQpqb2ludF90ZXN0cyhtb2RlbHMub2RkX3ZhbFtbMl1dLCBieT1jKCJTZXNzaW9uIiwgIlJ1biIpKSAKYGBgCjxicj4KPGJyPgogCgojIyMjIEhpdCtNaXNzIEpvaW50IFBsb3Qgey19CmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD01fQpwbG90Lm9kZF9yZXN1bHRzIDwtIGdnYXJyYW5nZSgKICBnZ2FycmFuZ2UoZ2dhcnJhbmdlKE5VTEwsIChwbG90Lm9kZF9zZXNzICsgeGxhYigiIikgKyBsYWJzKGNvbG9yPSIiLCBmaWxsPSIiKSArIHlsYWIoImRQcmltZSAoYS51LikiKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkgKSwKICAgICAgICAgICAgICAgICAgICAgIE5VTEwsIChwbG90Lm9kZF9oaXRzICsgeGxhYigiIikgKyB5bGFiKCJIaXRzIChjb3VudCkiKSt0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkpICksIAogICAgICAgICAgICAgICAgICAgICAgTlVMTCwgKHBsb3Qub2RkX2ZhcyArIHhsYWIoIiIpICsgeWxhYigiRmFsc2UgQWxhcm1zIChjb3VudCkiKSt0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkpICksIAogICAgICAgICAgICAgICAgICAgICAgbmNvbD02LCBjb21tb24ubGVnZW5kID0gVCwgbGVnZW5kPSJib3R0b20iLCB3aWR0aHM9YygwLjA1LCAxLCAwLjA1LCAxLCAwLjA1LCAxKSwgbGFiZWxzID1jKCJBIiwgIiIsICJCIiwgIiIsICJDIikpLAogIChwbG90LnNuX2Zhcyt5bGFiKCJGYWxzZSBBbGFybXMgKGNvdW50KSIpK3hsYWIoIlNOIEFjdGl2aXR5IChhLnUuKSIpKSwgbnJvdz0yLCBsZWdlbmQ9ImJvdHRvbSIsIGxhYmVscz1jKCIiLCAiRCIpKSkKCmBgYApgYGB7cn0KcGxvdC5vZGRfcmVzdWx0cwpnZ3NhdmUoImZpZ3VyZXMvRmlndXJlXzVfT2RkQmVoLnN2ZyIsIGRldmljZT0ic3ZnIiwgZHBpID0zMDAsIHdpZHRoPTUsIGhlaWdodCA9IDYpCmBgYAoKCiMjIyMgUlQgey0gLnRhYnNldH0KYGBge3J9CmRmX3Rhc2sub2RkcnQgPC0gZGZfdGFzayAlPiUgc3Vic2V0KHRhc2s9PTEgJiB2YWxlbmNlPT0wICYgcnQhPTApICU+JSBzdWJzZXQocnQ+MjAwKSAKZGZfdGFzay5vZGRydCR2YWxlbmNlIDwtIChzdHJfc3BsaXRfZml4ZWQoZGZfdGFzay5vZGRydCRzdGltdWx1cywgcGF0dGVybj0iXyIsIG4gPTMpKVssMl0KYGBgCgojIyMjIyBNb2RlbHMgey0gLmFjdGl2ZX0KYGBge3J9CiMgTWEKc2lnbmFscz1jKCIiLCAiU04iKQptb2RlbHMub2RkX3J0cyA8LSBtY21hcHBseShzaWduYWxzLCBGVU49ZnVuY3Rpb24oWCl7ZngucGFyX21vZGVsKHNpZ25hbD1YLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR2PSJydCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXY9aWZlbHNlKFg9PSIiLCAgIlNlc3Npb24qUGhhc2UiLCAiMStTZXNzaW9uKlBoYXNlKiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlPWlmZWxzZShYPT0iIiwgICIxK1Nlc3Npb24qUGhhc2UiLCBwYXN0ZSgiMStTZXNzaW9uKlBoYXNlKyIsIFgsIHNlcD0iIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Yl9pZD0ic3ViX2lkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW09R2FtbWEoImxvZyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfdGFzay5vZGRydCl9LCBtYy5jb3Jlcz01KQoKIyBQcmludCBIVE1MIE91dHB1dAphc2lzX291dHB1dCh0YWJfbW9kZWwobW9kZWxzLm9kZF9ydHMsIGR2LmxhYmVscyA9IGMoIlNpZ25hbCIsICJTaWduYWwgfiBTTiIpLCBzaG93LnN0YXQgPVQsIHNob3cuc2U9VCkka25pdHIpCmBgYAo8YnI+Cjxicj4KIAoKIyMjIyMgUG9zdC1Ib2M6IE1haW4gey19CmBgYHtyfQplbW1lYW5zKG1vZGVscy5vZGRfcnRzW1sxXV0sICBsaXN0KHBhaXJ3aXNlIH5TZXNzaW9uKlBoYXNlKSwgYnk9YygiUGhhc2UiKSwgYWRqdXN0ID0gInR1a2V5IikKYGBgCjxicj4KPGJyPgogCiMjIyMjIFBsb3Q6IE1haW4gey19CmBgYHtyfQpkZl90YXNrLm9kZHJ0X3N1bW0gPC0gc3VtbWFyeVNFd2l0aGluKGRmX3Rhc2sub2RkcnQsaWR2YXI9InN1Yl9pZCIsIG1lYXN1cmV2YXI9InJ0Iiwgd2l0aGludmFycyA9YygiU2Vzc2lvbiIsICJQaGFzZSIpKQpkZl90YXNrLm9kZHJ0X3N1bW0kUGhhc2UgPC0gYXMubnVtZXJpYyhhcy5mYWN0b3IoZGZfdGFzay5vZGRydF9zdW1tJFBoYXNlKSkKZGZfdGFzay5vZGRydF9zdW1tJFNlc3Npb24gPC0gcmVsZXZlbChkZl90YXNrLm9kZHJ0X3N1bW0kU2Vzc2lvbiwgIlN0cmVzcyIpCmdncGxvdChkZl90YXNrLm9kZHJ0X3N1bW0sIGFlcyh4PVBoYXNlLCB5PXJ0LCBjb2xvcj1TZXNzaW9uLCBmaWxsPVNlc3Npb24pKSArCiAgICBnZW9tX2xpbmUoKSArIAogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1ydC1zZSwgeW1heD1ydCtzZSwgY29sb3I9U2Vzc2lvbiksc2l6ZT0xLCB3aWR0aD0wLjE1LCBuYS5ybT1UKSsgCiAgZ2d0aGVtZTIgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMSwyLDMsNCw1LDYpKSAKYGBgCjxicj4KPGJyPgogCiMjIyMjIFBvc3QtSG9jOiBCcmFpbiB7LX0KYGBge3J9CmpvaW50X3Rlc3RzKG1vZGVscy5vZGRfcnRzW1syXV0sIGJ5PWMoIlNlc3Npb24iLCAiUGhhc2UiKSwgYWRqdXN0PSJub25lIikKYGBgCgoKIyMjIyMgTWVkaWF0aW9uIHstfQpgYGB7cn0KbGlicmFyeShtZWRpYXRpb24pCm1lZGlhdGlvbi5tZWQgPC0gbG1lNDo6bG1lcihTTiB+IFNlc3Npb24qUGhhc2UgKyAoMXxzdWJfbnIpLCBkYXRhPWRmX3Rhc2sub2RkcnQsIFJFTUw9RikKbWVkaWF0aW9uLm1haW4gPC0gbG1lNDo6bG1lcihsb2cxMChydCkgfiBTZXNzaW9uKlBoYXNlICsgU04gKyAoMXxzdWJfbnIpLCBkYXRhPWRmX3Rhc2sub2RkcnQsIFJFTUw9RikKbWVkaWF0aW9uLmFuYWx5c2lzIDwtIG1lZGlhdGUobW9kZWwubT1tZWRpYXRpb24ubWVkLCBtb2RlbC55PW1lZGlhdGlvbi5tYWluLCB0cmVhdCA9IlNlc3Npb24iLCBjb250cm9sLnZhbHVlPSJDb250cm9sIiwgbWVkaWF0b3IgPSAiU04iLCBzaW1zPTUwMDApCnN1bW1hcnkobWVkaWF0aW9uLmFuYWx5c2lzKQpgYGAKCiMjIyMgRkEgYnkgUlQgey0udGFic2V0fQoKIyMjIyMgTW9kZWxzIHstfQpgYGB7cn0KZGZfdGFzay5vZGRfcnRfZmEgPC0gZGZfdGFzay5vZGRydCAlPiUgZHBseXI6Omdyb3VwX2J5KHN1Yl9uciwgU2Vzc2lvbiwgUGhhc2UpICU+JSBkcGx5cjo6c3VtbWFyaXNlKHJ0PW1lYW4ocnQpKSAlPiUgZHBseXI6OnJlbmFtZShSdW49UGhhc2UpICU+JSB1bmdyb3VwKCkgJT4lIG1lcmdlKC4sIGRmX3Rhc2sub2RkLCBieT1jKCJzdWJfbnIiLCAiU2Vzc2lvbiIsICJSdW4iKSkKCm1vZGVsLm9kZF9mYV9ydCA8LSBsbWVyKHJ0IH4gU2Vzc2lvbipSdW4qb2RkX0ZBICsgKDErU2Vzc2lvbitSdW58c3ViX25yKSAsIAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRmX3Rhc2sub2RkX3J0X2ZhLCAKICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3Q9bGlzdChTZXNzaW9uPSJjb250ci50cmVhdG1lbnQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2w9bG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9ImJvYnlxYSIsIG9wdEN0cmw9bGlzdChtYXhmdW49MTAwMDAwKSkpCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtb2RlbC5vZGRfZmFfcnQpJGtuaXRyKQpjaGVja19tb2RlbChtb2RlbC5vZGRfZmFfcnQpCiNHYXVzIDI2NzAgI0dhdXNMb2cgMzMzNi4yOSAjIEdhbW1hIDc3NzAgI0dhbW1hIExvZwoKYGBgCgojIyMjIyBQb3N0LUhvYyB7LX0KYGBge3J9CmpvaW50X3Rlc3RzKG1vZGVsLm9kZF9mYV9ydCwgYnk9YygiU2Vzc2lvbiIsICJSdW4iKSwgYWRqdXN0PSJub25lIikKYGBgCgoKIyMjIyMgUGxvdCB7LX0KYGBge3J9CmVtbWlwKG1vZGVsLm9kZF9mYV9ydCwgU2Vzc2lvbiArIFJ1biB+IG9kZF9GQSwgY292LnJlZHVjZSA9IHJhbmdlKSsgZ2d0aGVtZTIjICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1zdHJlc3NfY29sb3JzKSAKYGBgCgoKCgpgYGB7cn0KcmNvcnIoZGZfdGFzay5vZGRfcnRfZmEkcnQsIGRmX3Rhc2sub2RkX3J0X2ZhJG9kZF9GQSkKcGxvdC5vZGRfZmFfcnQgPC0gZ2dwbG90KGRmX3Rhc2sub2RkX3J0X2ZhLCBhZXMoeD1vZGRfRkEsIHk9cnQpKSArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iICkKcGxvdC5vZGRfZmFfcnQgKyBmYWNldF9ncmlkKFNlc3Npb25+UnVuKQpgYGAKCgojIFN5c3RlbSBJbmZvCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoKCgoKCgo=